serviceWorker 能够实现资源、网络请求的缓存和处理,是 PWA 实现离线可访问、稳定访问、静态资源缓存的一项重要技术javascript
if ("serviceWorker" in navigator) { navigator.serviceWorker.register("./sw.js").then(function (registeration) { console.log(registeration); }); }
// sw.js 文件 var VERSION = "v1"; // install 阶段:安装sw,以后请求资源,并将资源缓存在cacheStorage中 self.addEventListener("install", function (event) { event.waitUntil( caches.open(VERSION).then(function (cache) { return cache.addAll([ "./start.html", "./static/jquery.min.js", "./static/mm1.jpg", ]); }) ); }); // 激活阶段:能够作些 除旧迎新的工做 // self.clients.matchAll() 能够获取浏览器全部的标签 self.addEventListener("activate", function (event) { event .waitUntil( caches.keys().then(function (cacheNames) { return Promise.all( cacheNames.map(function (cacheName) { // 若是当前版本和缓存版本不一致 if (cacheName !== VERSION) { return caches.delete(cacheName); } }) ); }) ) .then(function (cache) { // 这里能够判断若是cache里原本没有内容,表示第一次安装,就不用通知用户了 return self.clients.matchAll().then(function (clients) { if (clients && clients.length) { clients.forEach(function (client) { // 给每一个已经打开的标签都 postMessage client.postMessage("sw.update"); }); } }); }); }); // 拦截fetch请求阶段:捕获请求并返回缓存数据 self.addEventListener("fetch", function (event) { event.respondWith( caches .match(event.request) .catch(function () { return fetch(event.request); }) .then(function (response) { caches.open(VERSION).then(function (cache) { cache.put(event.request, response); }); return response.clone(); }) .catch(function () { return caches.match("./static/mm1.jpg"); }) ); });
navigator.serviceWorker.addEventListener("message", (event) => { console.log(event.data); });
scope 属性控制当前 sw 的做用范围
if ("serviceWorker" in navigator) { navigator.serviceWorker .register("./sw.js", { scope: "/demo" }) .then(function (registration) { console.log(registration); }); } // {scope:'/'} 表示做用在全部页面 // navigator.serviceWorker.register('/foo/sw.js',{scope:'/'}) 不会成功,由于sw 在foo路径下,而想要做用的倒是全局;越界了
当一个项目,存在多个 sw 时,会出现 sw 彼此干扰的问题(好比一个资源在多个 sw 做用域中);能够经过在注册以前,先行 unregister 的方法来解决html
navigator.serviceWorker.getRegistration() 获取页面全部注册的 serviceWorker
navigator.serviceWorker.getRegistration().then(function (regs) { for (var reg of regs) { reg.unregister(); } });
一、服务器端控制前端
location ~ \/sw\.js${ add_header Cache-Control no-store; add_header Pragma no-cache; }
二、前端使用版本控制java
// 这种方式不行,会触发死循环 if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js?v=" + Date.now()); }
使用 sw-register.js 文件jquery
// sw-register.js if('serviceWorker' in navigator){ navigator.serviceWorker.register('/sw.js?v=201807041262') } // index.html <script> window.onload=function(){ var script=document.createElement('script'); var firstScript=this.document.getElementByTagName('script')[0]; script.type="text/javascript"; script.async=true; script.src="/sw-register.js?v="+Date.now(); firstScript.parentNode.insertBefore(script,firstScript) } </script>
Q:若是 SW 运行过程当中,出现了问题怎么办?
A: 须要 找个能快速上线的开关 JS 文件 https://yourhost.com/switch.jsgit
默认 SW_FALLBACK=false ;紧急状况 SW_FALLBACK=true;github
<script> window.onload=function(){ var firstScript=document.getElementByTagName('script')[0]; var fbScript=document.createElement("script"); fbScript.type="text/javascript"; fbScript.async=true; fbScript.src="https://yourhost.com/switch.js?v="+Date.now(); firstScript.parentNode.insertBefore(fbScript,firstScript); fbScript.onload=function(){ if('serviceWorker' in navigator && window.SW_FALLBACK){ //getRegistration 的参数为sw的scope值 navigator.serviceWorker.getRegistration('/').then(function(reg){ reg && reg.unregister(); }) } } } </script>
sw 应用场景不少,好比后端消息推送等等,由于时间缘由,没有详细了解这块,能够参考这篇
使用 Service Worker 发送 Push 推送chrome
总体文章,可能会有些问题,若有疑问,欢迎留言或者微信交流,共同窗习进步!后端
ServiceWorker MDN
Service Worker 最佳实践
Service Worker 应用
service-worker
借助 Service Worker 和 cacheStorage 缓存及离线开发