service worker如何用在vue 或者react 项目中使用
function registerSw(){
if('serviceWorker' in window.navigator){
navigator.serviceWorker.register('/ggtest.js').then(res=>{
console.log('success')
}).catch(err=>{
console.log('fail')
})
}
}
module.exports= registerSw
然后在 项目入口文件引入,并调用方法
现在来说注意事项, navigator.serviceWorker.register('/service-worker.js') ,/service-worker.js 文件所在位置是指基于打包或者编译后的位置。不是当前的引用位置。但是因为目前vue和react项目基本上大部分都是基于webpack 打包,会将文件打包,然后生成hash值,导致引用异常。
解决方案:copy-webpack-plugin 插件 使用方式:
// 不传 默认就是打包后的根目录 ,另外webpack5 在写法上有调整。
new CopyWebpackPlugin([{ from: path.resolve(__dirname, '../static') }])
//webpack5
new CopyWebpackPlugin({patterns: [{ from: path.resolve(__dirname, '../static') }]}),
缓存静态文件和get请求的,网上一堆的资料,可以自己去看下。主要是讲一下如何缓存post请求
首先判断一下当前是不是个post请求
this.addEventListener('fetch',function(event){
if(event.request.method =='POST'){
...
}
})
首先明确一下 catchStorage 是不支持存储 post 请求的,并且service worker 不是运行在主线程的,是没有window对象的。所以只能使用indexdb去做存储。所以我们需要引入一个封装过的indexdb 库 dexie.js,(dexie.js文件地址也是打包后的地址,然后不是通过import 或者require 方法,不支持)
importScripts('/static/dexie.js')
this.addEventListener('fetch',function(event){
if(event.request.method =='POST'){
// dexie 使用
var db = new Dexie('post_cache');
db.version(1).stores({
post_cache: 'key, response,token, timestamp'
// post_cache 表名
// key, response,token, timestamp 四个都是字段名
})
// 这样就开起了一个post_cache的indexdb库下的post_cache表
...
}
})
首先来个常规写法,就是正常还是走接口请求,但是接口异常时才走缓存数据。
this.addEventListener('fetch',function(event){
// console.log('fetch window',window)
if(event.request.method =='POST'){
var db = new Dexie('post_cache');
db.version(1).stores({
post_cache: 'key, response,token, timestamp'
})
event.respondWith(
fetch(event.request.clone())
.then(function(response) {
// 后面讲
cachePut(event.request.url, response.clone(),db.post_cache);
return response;
})
.catch(function() {
//后面讲
return cacheMatch(event.request.url,db.post_cache)
})
)
}
});
首先来讲一下,cachePut 函数吧,先描述一下吧,因为所有的service worker的操作都是异步操作,所以先要通过方法异步去获取数据,并且等数据转换好了之后再去添加到indexdb中保存,先上代码:
// 获取请求头里面的所有的参数
function serializeHeaders(headers) {
var serialized = {};
for (var entry of headers.entries()) {
serialized[entry[0]] = entry[1];
}
return serialized;
}
//
function serializeResponse(response) {
var serialized = {
headers: serializeHeaders(response.headers),
status: response.status,
statusText: response.statusText,
ok:response.ok,
bodyUsed:response.bodyUsed,
type:response.type,
url:response.url
};
// serialized 这个对象就是按照接口返回的数据结构构造的,但是没有 body
return Promise.resolve(serialized);
}
function cachePut(defaultUrl, response,token, store) {
serializeResponse(response.clone()).then((resp)=>{
....
}
}
现在来看下是如何获取body的吧
function cachePut(defaultUrl, response,token, store) {
serializeResponse(response.clone()).then((resp)=>{
// body 又是一层 异步
response.clone().text().then(res=>{
let body = {...resp,body:res}
// entry 就是我们需要存入indexdb的数据
var entry ={
key :defaultUrl,
response:body,
token,
timestamp: Date.now()
}
store.add(entry).catch(function(error){
// 当添加数据异常的时候尝试更新数据
store.update(entry.key,entry)
})
})
})
}
到这里数据存完了,但是总得用吧。(手动斜眼笑),这就来到了我们 cacheMatch 方法了
function deserializeResponse(data) {
// 返回的数据一定要是一个异步数据,并且是一个Response对象。
return Promise.resolve(new Response(data.body, data));
}
function cacheMatch(requestUrl,token,store) {
return store.get(requestUrl).then(function(data){
// 获取数据
if (data) {
// 用户切换身份,token 这个主要是为了防止接口缓存了,但是用户身份切换了接口未更新导致《加班》
if(data.token != token ){
return undefined
}
return deserializeResponse(data.response);
} else {
//未取到数据
return undefined
}
});
}
到了这里,现在来介绍一下如何优先缓存其次是fetch了。
this.addEventListener('fetch',function(event){
if(event.request.method =='POST'){
var db = new Dexie('post_cache');
db.version(1).stores({
post_cache: 'key, response,token, timestamp'
})
event.respondWith(
async function() {
var token = ''
const reqHead = event.request.clone().headers
for (var entry of reqHead.entries()) {
if(entry[0] =='j_token'){
token = entry[1]
}
}
const response = await cacheMatch(event.request.url,token,db.post_cache)
return response || fetch(event.request.clone())
.then(function(response) {
cachePut(event.request.url, response.clone(), token,db.post_cache);
return response;
})
}()
)
}
});