Service Workers 不只能够应用于PWA
,PC 端也能够利用其强大的功能实现一些有趣的优化,网络中有不少关于 Service Workers 介绍的比较好的文章,基于小册宗旨,本文并非一篇Service Workers
的详细教程。
Service worker 是一个注册在指定源和路径下的事件驱动 worker。css
它运行在 worker 上下文中,不能访问 DOM,相对于驱动应用的主 JavaScript 线程,它运行在其余线程中,因此不会形成阻塞。html
它采用 JavaScript 控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你能够彻底控制应用在特定情形(最多见的情形是网络不可用)下的表现。vue
它设计为彻底异步,同步 API(如 XHR 和 localStorage)不能在 Service worker 中使用。webpack
在已经支持 serivce worker
的浏览器的版本中,不少特性没有默认开启,web
了解浏览器对 serivce worker 的支持性。
若是你发现示例代码在当前版本的浏览器中怎么样都没法正常运行,你可能须要开启一下浏览器的相关配置。chrome
另外,须要注意的是,出于安全缘由 Service Workers 要求必须在 HTTPS 下才能运行,为了便于本地开发,localhost
也被浏览器认为是安全源。bootstrap
使用 ServiceWorkerContainer.register()
函数来注册站点的 service worker
(service sorker
只是一个 JavaScript 脚本)。segmentfault
注意,这个文件的url
是相对于origin
, 而不是相对于引用它的那个 JS 文件。
<!-- index.html --> <script> if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/serviceworker.js") .then(function(reg) { if(reg.installing) { console.log('Service worker installing'); } else if(reg.waiting) { console.log('Service worker installed'); } else if(reg.active) { console.log('Service worker active'); } }) .catch(console.error); } </script>
在 Service Worker
注册以后,浏览器会尝试为你的页面或站点安装并激活它。 数组
install
事件会在注册完成以后触发,install
事件通常是被用来填充你的浏览器的缓存能力。浏览器
为了达成这个目的,咱们使用了 Service Worker
的新的标志性的存储 API — Cache
,一个 service worker 上的全局对象,它使咱们能够存储网络响应发来的资源,而且根据它们的请求来生成 key
。
Cache 接口像 workers 同样,是暴露在 window 做用域下的,尽管它被定义在 service worker 的标准中, 可是它没必要必定要配合 service worker 使用。
// serviceworker.js const cacheName = 'my-cache'; // self 表明 worker 线程自身,即子线程的全局对象 self.addEventListener('install', event => { // 用来存放缓存的静态资源和路由 const filesToCache = [ '/', '/static/css/reset.css', '/static/css/css-loader.css', '/static/css/create-version.css', '/static/css/bootstrap-grid.css', '/static/css/bootstrap.css', '/static/js/css-animations.js', '/static/js/vue.js', ]; event.waitUntil( // caches 是 CacheStorage 的实例子:caches instanceof CacheStorage -> true // 使用 CacheStorage.open(cacheName) 打开一个 Cache 对象 caches.open(cacheName) // 将字符串 URL 数组添加到缓存中 .then(cache => cache.addAll(filesToCache)) .catch(e => console.error(e)) ); });
这里咱们新增了一个 install
事件监听器,接着在事件上接了一个 ExtendableEvent.waitUntil() 方法。
waitUntil()
用来确保 service worker 不会在 waitUntil()
里边的代码执行完毕以前安装完成。
若是caches.open(cacheName)
被rejected
,安装就会失败,这个worker
不会作任何事情(例如:URL 拼写错误)。
注意:首次注册/激活 Service Worker
线程的页面须要再次加载才会受其控制(二次生效)。在成功安装完成并处于激活状态以前,Service Worker
线程不会收到 fetch
(下文会提到)和 push
事件。
如今已经将站点资源缓存了,还须要告诉 Service Worker
让它用这些缓存内容来作点什么,咱们能够借助 fetch API 进行一层拦截。
//fetch 事件处理程序,拦截请求并应用于全部缓存中的静态资产 self.addEventListener('fetch', e => { e.respondWith( caches.match(e.request) .then(response => response ? response : fetch(e.request)) ) });
caches.match(event.request)
容许咱们对网络请求的资源和 cache
里可获取的资源进行匹配,查看是否缓存中有相应的资源。这个匹配经过 url
和 vary header
进行,就像正常的 http
请求同样。
查看 Fetch API documentation 了解更多有关 Request 和 Response 对象的更多信息。
当匹配到 catch
资源时,caches.match(event.request)
就会 resolve
,在 then
回调中就能够直接返回 response
。
caches.match(e.request) .then(response => response)
若是没有匹配到资源,caches.match(event.request)
就会 reject
,能够告诉浏览器直接使用 fetch
进行默认的网络请求。(意味着在网络可用的时候能够直接像服务器请求资源)
caches.match(e.request) .then(response => response ? response : fetch(e.request))
更新缓存清单,能够借助 activate
事件进行处理,本文案例代码并无对其进行实现。
只是使用 clients.claim() 对页面进行控制权获取,这样以后打开页面都会使用版本更新的缓存。
self.addEventListener('activate', e => self.clients.claim());
SPA
项目中因为引入 hash
会引发 URL 的变化,在这种状况下如何更新 Service Worker
的缓存,推荐这篇 service worker 在移动端 H5 项目的应用。Chrome 有一个chrome://inspect/#service-workers
能够展现当前设备上激活和存储的 service worker。还有个chrome://serviceworker-internals
能够展现更多细节来容许你开始/暂停/调试 worker 的进程。
经过 Chrome devTools
的 Application Tab
咱们能够查看当前服务工做线程的运行状况。
附 serviceworker.js
完整代码:
const cacheName = 'my-cache'; // self.clients.claim() 取得页面控制权,这样以后打开页面都会使用版本更新的缓存 self.addEventListener('activate', e => self.clients.claim()); self.addEventListener('install', event => { // 用来存放缓存的静态资源和路由 const filesToCache = [ '/', '/static/css/reset.css', '/static/css/css-loader.css', '/static/css/create-version.css', '/static/css/bootstrap-grid.css', '/static/css/bootstrap.css', '/static/js/css-animations.js', '/static/js/vue.js', ]; event.waitUntil( // caches 是 CacheStorage 的实例子:caches instanceof CacheStorage -> true // 使用 CacheStorage.open(cacheName) 打开一个 Cache 对象 caches.open(cacheName) // 将 filesToCache (字符串 URL 数组)添加到缓存中 .then(cache => cache.addAll(filesToCache)) .catch(e => console.error(e)) ); }); // fetch 进行拦截 self.addEventListener('fetch', e => { e.respondWith( caches.match(e.request) .then(response => { return response ? response : fetch(e.request) }) ) });
延伸阅读推荐:这篇文章。
同系列文章: