基本特性
不能直接访问/操作 DOM(只能使用特定的 API:Promise、Fetch API、Cache API)
需要时直接唤醒,不需要时自动休眠
离线缓存内容开发者可控
一旦被安装则永远存活,除非手动卸载
必须在 HTTPS 环境下工作(本地环境 localhost 除外)
广泛使用了 Promise
使用
生命周期相关知识
install 阶段缓存文件列表
activate 阶段清理缓存
fetch 拦截请求
注册
main.html 下
// 同域下允许注册多个不同 scope 的 service worker
if ('serviceWorker' in navigator) {
// 缩短白屏时间
window.addEventListener('load', function () {
// scope:指定访问的域
navigator.serviceWorker.register('/static/sw-demo.js', { scope: '/static' })
.then(registration => { // 注册成功
console.log(registration.scope);
})
.catch(error => { // 注册失败
})
})
}
安装
sw-demo.js 下
const myCache = {
NAME: 'my-cache-v0',
data: [
'/',
'/test.js',
'test.css'
]
}
this.addEventListener('install', function (event) {
// 控制安装阶段流程,只有里面的 resolve 了,安装阶段才结束
event.waitUntill(
caches.open(myCache.NAME) // 开辟缓存区
.then(cache => {
// 缓存指定文件列表(注意文件缓存列表过长,会增加缓存失败的概率)
return cache.addAll(myCache.data)
})
)
})
激活
sw-demo.js 下
this.addEventListener('activate', function (event) {
// 控制激活阶段流程,只有里面的 resolve 了,激活阶段才结束
event.waitUntill(
Promise.all([
// 跳过刷新页面的过程,让其立即具备所有的正常功能
this.clients.claim(),
caches.then((cacheList) => {
return Promise.all(
cacheList.map(cacheName => {
// 监测缓存如果不匹配则丢弃缓存
if (cacheName !== myCache.NAME) {
return caches.delete(cacheName)
}
})
)
})
])
)
})
案例
main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', function (event) {
navigator.serviceWorker.register('/sw.js', {
scope: '/'
})
.then(function (registeration) {
console.log('Service worker register success with scope ' + registeration.scope);
});
});
navigator.serviceWorker.oncontrollerchange = function (event) {
ui.showToast('页面已更新', 'info');
};
// 如果用户处于断网状态进入页面,用户可能无法感知内容是过期,需要提示用户断网了,并在重新连接后告诉用户
if (!window.navigator.onLine) {
ui.showToast('网络断开,内容可能已过期', 'info');
window.addEventListener('online', function () {
ui.showToast('已连接网络', 'info');
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sw.js
const my_cache = {
CACHE_NAME: 'cache_v_0',
CACHE_URLS: [
'/',
'/js/ui.js',
'js/render.js',
'/js/main.js',
'/api/movies',
'/css/main.css',
'/img/logo.png'
]
}
// 下载新的缓存
self.addEventListener('install', function (event) {
event.waitUntil(
precache().then(self.skipWaiting)
);
});
// 删除就的缓存
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
self.clients.claim(),
clearStaleCache()
])
);
});
self.addEventListener('fetch', function (event) {
// 只对同源的资源走 sw,cdn 上的资源利用 http 缓存策略
if (new URL(event.request.url).origin !== self.origin) {
return;
}
if (event.request.url.includes('/api/movies')) {
event.respondWith(
fetchAndCache(event.request)
.catch(function () {
return caches.match(event.request);
})
);
return;
}
event.respondWith(
fetch(event.request).catch(function () {
return caches.match(event.request);
})
);
});
/**
* 缓存到 cacheStorage 里
*
* @param {Request} req 请求对象
* @param {Response} res 响应对象
*/
function saveToCache(req, res) {
return caches
.open(my_cache.CACHE_NAME)
.then(cache => cache.put(req, res));
}
/**
* 预缓存
*
* @return {Promise} 缓存成功的promise
*/
function precache() {
return caches.open(my_cache.CACHE_NAME).then(function (cache) {
return cache.addAll(my_cache.CACHE_URLS);
});
}
/**
* 清除过期的 cache
*
* @return {Promise} promise
*/
function clearStaleCache() {
return caches.keys().then(keys => {
keys.forEach(key => {
if (my_cache.CACHE_NAME !== key) {
caches.delete(key);
}
});
});
}
/**
* 请求并缓存内容
*
* @param {Request} req request
* @return {Promise}
*/
function fetchAndCache(req) {
return fetch(req)
.then(function (res) {
saveToCache(req, res.clone());
return res;
});
}
成熟缓存工具
sw-precache 预缓存
sw-toolbox 动态缓存
workbox 集大成者
————————————————
版权声明:本文为CSDN博主「肖ZE」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lucky541788/article/details/100089079