余为前端菜鸟,感姿式水平匮乏,难观前端之大局。遂决定循前端知识之脉络,以兴趣为引,辅以几分坚持,望于己能解惑致知、于同道能助力一二,岂不美哉。html
本系列代码及文档均在 此处前端
service worker是一个由来已久的HTML5 API,旨在建立持久的离线缓存。相似于web worker,都是在浏览器后台单独开的一个线程内工做,能够向客户端推消息,不可操做dom。git
service worker有本身的worker context,能够拦截请求和返回,缓存文件,必须在HTTPS或者本地环境下运行,异步实现,内部大部分经过Promise实现github
依赖Cache API,依赖FTML5 fetch API,依赖Promise实现离线缓存功能web
parsed -> installing -> installed -> activating -> activated -> redundantchrome
注册在主线程中进行api
if (navigator.serviceWorker) {
// register异步方法
navigator.serviceWorker.register('./sw.js', { scope: '/' }).then(() => {
console.log('sw service worker 注册成功')
console.log('parsed ----> installing')
}).catch((err) => {
console.log(err)
})
}
复制代码
在worker的脚本文件中监听install事件,能够维护初始缓存列表浏览器
self.addEventListener('install', (event) => {
// 确保安装完成前完成下面的操做
event.waitUntil(
// 建立一个cache
caches.open('v1').then((cache) => {
// cache是缓存实例
// 调用该实例的addAll方法提早加载相关文件进缓存
return cache.addAll([
'/html/test.js',
'/html/default.html'
])
})
console.log('installing ----> installed ----> activating')
)
// self.skipWaiting() 直接进入activate
})
复制代码
worker安装完成后会转为installed/activating状态,在知足如下条件之一时能够转为activate状态缓存
activated状态会触发activate回调,在worker监本中监听activate事件app
self.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.filter(function (cacheName) {
return cacheName != 'v1';
}).map(function (cacheName) {
// 清除旧的缓存
return caches.delete(cacheName);
})
)
})
console.log('activating ----> activated')
)
// self.clients.claim() 获取页面控制权,旧的worker失效
})
复制代码
激活后能够控制页面行为,能够处理功能事件,如fetch
, push
, message
符合worker的scope内的资源请求都会触发fetch被控制
self.addEventListener('fetch', function (event) {
// 利用respondWith劫持响应
event.respondWith(
caches.open('v1').then(function (cache) {
return cache.match(event.request).then(function (response) {
// match到则返回不然直接请求
return response || fetch(event.request).then(function (response) {
// 404抛错到catch处理
if (response.status === 404) {
throw new Error('nothing')
}
// 将response做为value存入cache
// install时能够进行缓存
// 劫持fetch时也能够进行动态资源缓存
cache.put(event.request, response.clone());
return response;
}).catch((err) => {
// 返回cache storage里存的默认页面
return caches.match('/html/default.html');
});
});
})
);
});
复制代码
localStorage是同步的,因此不能用于service worker内的存储,IndexedDB能够用
安装失败、激活失败、被新的worker取代时转入废弃状态
当service worker脚本内容更新时,会安装新的文件并触发install,转入installed/waiting状态。此时旧的worker仍处于激活状态,在页面关闭后会被废弃,此后新开页面里新的worker才会生效
上图为更改sw.js
后刷新页面的结果,关闭页面重开后1497将是激活中的worker
通常为24小时
// 跳过等待,直接进入activate
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
// actived以前更新客户端
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 更新客户端全部的service worker
self.clients.claim(),
// 清理旧版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'v1') {
return caches.delete(cacheName);
}
})
)
})
])
)
)}
复制代码
主线程内每次注册时进行更新
var version = '1.0';
navigator.serviceWorker.register('./sw.js').then(function (reg) {
if (localStorage.getItem('sw_version') !== version) {
// reg.update
reg.update().then(function () {
localStorage.setItem('sw_version', version)
});
}
});
复制代码
debug时更新
self.addEventListener('install', function () {
if (ENV === 'development') {
// 每次刷新页面从新注册安装时直接进入activate,确保最新
self.skipWaiting();
}
});
复制代码
cacheStorage是在serviceworker规范中定义的接口,咱们可使用全局的caches访问cacheStorage
caches经常使用api有: open
, match
, delete
, has
, keys
代码位于github
本地利用koa-static
建一个静态页面的server
const Koa = require('koa')
const path = require('path')
const static = require('koa-static')
const app = new Koa()
const staticPath = './frontend/basic'
app.use(static(
path.join(__dirname, staticPath)
))
复制代码
页面中插入脚本
window.addEventListener('load', function () {
if (navigator.serviceWorker) {
navigator.serviceWorker.register('./sw.js').then(() => {
console.log('sw service worker 注册成功')
}).catch((err) => {
console.log(err)
})
}
})
复制代码
sw.js
见 github
offline模式下,能够从cache中读取文件缓存
不存在的资源路径返回缓存好的default.html
二次访问缓存list内的资源时劫持请求和响应,返回缓存内容
虽发表于此,却毕竟为一人之言,又是每日学有所得之笔记,内容未必详实,看官老爷们还望海涵。