Service Worker 基本用法

看了不少介紹Service Worker的,看得都挺模糊的,因此決定本身寫一篇文件整理一下思路。html

1、Service Worker API 名詞區分

一、ServiceWorkerContainer:navigator.serviceWorker返回的就是Service WorkerContainer對象,主要是用戶在頁面註冊serviceWorker,調用方法:web

navigator.serviceWorker.register(scriptURL, options)
    .then(function(ServiceWorkerRegistration) { ... })

二、ServiceWokrerGlobalScope:主要是用戶在sw.js文件的全局變量,即this的指向
三、ServiceWorkerRegistration:在頁面調用serviceWorker.register註冊返回一個Promise對象,當resolve時傳遞給then的函數參數就是ServiceWorkerRegistration.
四、ServiceWorker:表示ServiceWorkerRegistration.installing || ServiceWorkerRegistration.waiting || ServiceWorkerRegistration.active數據庫

2、Service Worker 註冊

一、index.htmlsegmentfault

<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>

二、sw.jspromise

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是否在緩存中,若是在則返回內容,若是不在,則向服務端發起請求數據,將返回的數據放入緩存中而且返回給瀏覽器。
代碼中的方法解析:
一、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 值, 表示所要搜索的緩存名稱。

二、caches.open():返回一個resolve爲匹配 cacheName 的 cache 對象的 Promise .若是指定的 cache 不存在,則使用該 cacheName 建立一個新的cache並返回。ide

caches.open(cacheName).then(function(cache) {});

三、cache.addAll():將靜態資源加入緩存中函數

cache.addAll(requests[]).then(function() {
  // 已加入緩存
});

該方法會覆蓋掉之前存儲在緩存中的匹配的健值對,可是後面監聽對fetch事件中調用cache.put()方法又會覆蓋掉以前在cache.addAll()中添加到緩存中所匹配的健值對。
四、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
});

五、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)
六、event.respondWith():阻止瀏覽器默認的fetch處理方法,容許用戶本身提供一個promise對象做爲response返回。

fetchEvent.respondWith(
  // Promise that resolves to a Response.
​)

Parameters:A Promise for a Response.

上面的sw.js只是一個最基本的serviceWorker,在平常工做中,咱們還須要考慮更新。

3、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加載的頁面。

(二)手動更新

手動更新主要是調用在index.html註冊serviceWorker時的registration的update()方法:ServiceWorkerRegistration.update();
它會獲取worker的腳本URL,若是新的worker與當前的worker並非徹底相同的(byte-by-byte identical)則安裝新的worker;若是前一次worker獲取發生在24小時以前,則worker的獲取將繞過任何瀏覽器緩存。

navigator.serviceWorker.register('./sw.js').then(function(registration){
   registration.update();
});

參考學習連接:
https://developer.mozilla.org...
https://developers.google.cn/...
https://lavas.baidu.com/pwa/o...
https://segmentfault.com/a/11...

相關文章
相關標籤/搜索