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) }) ) });
延伸閱讀推薦:這篇文章。
同系列文章: