Service Worker 基本用法
看了很多介紹Service Worker的,看得都挺模糊的,所以決定自己寫一篇檔案整理一下思路。
一、Service Worker API 名詞區分
1、ServiceWorkerContainer:navigator.serviceWorker返回的就是Service WorkerContainer物件,主要是使用者在頁面註冊serviceWorker,呼叫方法:
navigator.serviceWorker.register(scriptURL, options) .then(function(ServiceWorkerRegistration) { ... })
2、ServiceWokrerGlobalScope:主要是使用者在sw.js檔案的全域性變數,即this的指向
3、ServiceWorkerRegistration:在頁面呼叫serviceWorker.register註冊返回一個Promise物件,當resolve時傳遞給then的函式引數就是ServiceWorkerRegistration.
4、ServiceWorker:表示ServiceWorkerRegistration.installing || ServiceWorkerRegistration.waiting || ServiceWorkerRegistration.active
二、Service Worker 註冊
1、index.html
<script> // register if("serviceWorker" in navigator){ navigator.serviceWorker.register('./sw.js') .then(function(registration){ console.log("Register success: ",registration.scope); }); .catch(function(err){ console.log("Register failed: ",err); }); }else{ console.log('Service workers are not supported.'); } </script>
2、sw.js
var CACHE_NAME = 'sw-test-v1'; this.addEventListener('install',function(event){ console.log("installing..."); event.waitUntil(caches.open(CACHE_NAME).then(function(cache){ cache.addAll([ 'images/resource01.jpg', 'images/resource02.jpg', .... ]); })); }); this.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { // 快取命中,返回快取 return response; } // 請求是stream資料,只能使用一次,所以需要拷貝,一次用於快取,一次用於瀏覽器請求 var fetchRequest = event.request.clone(); return fetch(fetchRequest) .then(function(response) { if(!response || response.status !== 200) { return response; } // 響應也是stream,只能使用一次,一次用於快取,一次用於瀏覽器響應 var responseToCache = response.clone(); caches.open(CACHE_NAME) .then(function(cache) { cache.put(event.request, responseToCache); }); return response; }); }) ); });
sw.js工作內容:首先監聽install事件,呼叫cache.addAll()方法將靜態資源加入快取中。然後監聽fetch事件,判斷當前請求的url是否在快取中,如果在則返回內容,如果不在,則向服務端發起請求資料,將返回的資料放入快取中並且返回給瀏覽器。
程式碼中的方法解析:
1、caches.match():檢查給定的Request物件或url字串是否是一個已儲存的 Response物件的key. 該方法針對 Response 返回一個 Promise ,如果沒有匹配則返回 undefined 。cache物件按建立順序查詢,等同於在每個快取上呼叫 cache.match() 方法 (按照caches.keys()返回的順序) 直到返回Response 物件。語法如下:
caches.match(request, options).then(function(response) { // Do something with the response });
引數解析:
options: 可選,配置物件中的屬性控制在匹配操作中如何進行匹配選擇,具體屬性如下:
- ignoreSearch: Boolean值, 指定匹配過程是否應該忽略url中查詢引數,預設 false。
- ignoreMethod:Boolean 值,當被設定為 true 時,將會阻止在匹配操作中對 Request請求的 http 方式的驗證 (通常只允許 GET 和 HEAD 兩種請求方式)。該引數預設為 false.
- ignoreVary:Boolean 值,當該欄位被設定為 true, 告知在匹配操作中忽略對VARY頭資訊的匹配。換句話說,當請求 URL 匹配上,你將獲取匹配的 Response 物件,無論請求的 VARY頭存在或者沒有。該引數預設為 false.
- cacheName:DOMString 值, 表示所要搜尋的快取名稱。
2、caches.open():返回一個resolve為匹配 cacheName 的 cache 物件的 Promise .如果指定的 cache 不存在,則使用該 cacheName 建立一個新的cache並返回。
caches.open(cacheName).then(function(cache) {});
3、cache.addAll():將靜態資源加入快取中
cache.addAll(requests[]).then(function() { // 已加入快取 });
該方法會覆蓋掉以前儲存在快取中的匹配的健值對,但是後面監聽對fetch事件中呼叫cache.put()方法又會覆蓋掉之前在cache.addAll()中新增到快取中所匹配的健值對。
4、cache.put():允許將鍵/值對新增到當前的 Cache 物件中.它將覆蓋先前儲存在匹配請求的cache中的任何鍵/值對。
注意: Cache.add/Cache.addAll 不會快取 Response.status 值不在200範圍內的響應,而 Cache.put 允許你儲存任何請求/響應對。因此,Cache.add/Cache.addAll 不能用於不透明的響應,而 Cache.put 可以。
cache.put(request, response).then(function() { // request/response pair has been added to the cache });
5、event.waitUntil():擴充套件了事件的生命週期。在服務工作執行緒中,延長事件的壽命從而阻止瀏覽器在事件中的非同步操作完成之前終止服務工作執行緒。
在install 事件中,它延遲將被安裝的worker視為 installing ,直到傳遞的 Promise 被成功地resolve。主要用於確保:服務工作執行緒在所有依賴的核心cache被快取之前都不會被安裝。
在activate 事件中,它延遲將 active worker視為已啟用的,直到傳遞的 Promise 被成功地resolve。這主要用於確保:任何功能事件不會被分派到 ServiceWorkerGlobalScope 物件,直到它升級資料庫模式並刪除過期的快取條目。
當該方法執行時,如果 Promise 是resolved,任何事情都不會發生;如果 Promise 是rejected,installing 或者 active worker的 state 會被設定為redundant。
語法:event.waitUntil(promise)
6、event.respondWith():阻止瀏覽器預設的fetch處理方法,允許使用者自己提供一個promise物件作為response返回。
fetchEvent.respondWith( // Promise that resolves to a Response. )
Parameters:A Promise for a Response.
上面的sw.js只是一個最基本的serviceWorker,在日常工作中,我們還需要考慮更新。
三、Service Worker更新
(一)自動更新
this.addEventListener('install',function(event){ this.skipWaiting(); }); this.addEventListener('activate', function (event) { this.clients.claim(); });
skipWaiting(): 強制等待中的service worker跳過等待成為啟用的service worker。雖然該方法在任何時候都是可以呼叫的,但是隻有在新安裝的service worker仍然處於等待狀態時才會起作用;所以在install事件裡面呼叫是非常常見的。與clients.claim()一起呼叫以確保更新當前的client和其他啟用的clients。
clients.claim(): 允許一個啟用的service worker將其設定為其他同scope下的clients的controller。該方法會觸發要被該service worker控制的其他任何clients的navigator.serviceWorker上的"controllerchange"事件。
當一個service worker初始註冊時並不會使用該service worker,直到下次載入頁面時。該方法會讓這些頁面直接被控制,注意,這將導致你的service worker將控制定期載入的頁面,也有可能控制其他service worker載入的頁面。