PWA進階 - cache機制
前言
前一陣子為了要讓Web像是App一樣可以接收推播,於是在網頁新增了PWA(原文在此),在上篇文章中PWA的部分只是簡單的帶過,所以今天特地寫了一個主題來介紹PWA及cache機制。
Service worker 代碼
找到public下的 sw.js
並修改
javascript1const CACHE_NAME = "v1"; 2 3self.addEventListener("install", (event) => { 4 event.waitUntil( 5 caches.open(CACHE_NAME).then((cache) => { 6 return cache.addAll(["/", "/index.html", "/logo192.png"]); 7 }) 8 ); 9 self.skipWaiting(); 10}); 11 12self.addEventListener("activate", (event) => { 13 event.waitUntil( 14 caches 15 .keys() 16 .then((cacheNames) => { 17 return Promise.all( 18 cacheNames.map((cacheName) => { 19 if (cacheName !== CACHE_NAME) { 20 return caches.delete(cacheName); 21 } 22 }) 23 ); 24 }) 25 .then(() => { 26 return self.clients.claim(); 27 }) 28 ); 29}); 30 31self.addEventListener("fetch", (event) => { 32 event.respondWith( 33 caches.match(event.request).then((response) => { 34 if (response) { 35 return response; 36 } 37 return fetch(event.request).then((networkResponse) => { 38 return caches.open(CACHE_NAME).then((cache) => { 39 if ( 40 event.request.method === "GET" && 41 event.request.url.includes("/static") 42 ) { 43 cache.put(event.request, networkResponse.clone()); 44 } 45 return networkResponse; 46 }); 47 }); 48 }) 49 ); 50});
代碼介紹
CACHE_NAME
版本名稱,用來判斷service worker版本是否更新。
install
在此會載入新的service worker並且將你設定的靜態檔給cache住,cache後就可以在離線的情況下運行,就是像真的App一樣。
skipWaiting
在service worker的機制中,會等到舊的service worker終止後才會執行新的service worker,但舊的service worker只有在網頁被關掉時侯後或是重新整理才會終止,所以這時候就可以透過 skipWaiting()
直接讓新的service worker開始運行。
activate
舊的service worker被卸載後,新的service worker就會觸發activate,所以我們可以透過 CACHE_NAME
這個變數來判斷版本是否有改變,若版本改變了就把舊有的cache給清除掉。
claim
claim()
此方法是為了service worker立即生效而不用重新加載。
這邊讀者可能會有疑問,明明已經透過 skipWaiting()
讓新的service worker開始運行了為甚麼還需要 claim()
。
這裡舉個例子: 假設你在第一個分頁開起網頁後service worker的版本是 v1
,這時候網站更新了 v2
版本,接著你在第二個分頁開啟的網頁service worker版本會就會是 v2
,這就會導致你開了同樣的頁面但功能卻有所不同,此時就可以使用 claim()
該方法,將第一個分頁的service worker變成 v2
版,而不用關閉該網頁或重新整理。
fetch
在此會做兩件事:
- 判斷網頁要拿得資源是cache的還是線上的。
- 是否要將新獲取的資源放入cache中。
這邊讀者可能會提問,為何不把需要cache的資源在install的時候就設定好。
看上圖可以知道我載入了名為 main.5fd0f9d6.js
的檔案,但 5fd0f9d6
是一個hash值,在每次build專案時都會不一樣,所以我們無法在install階段就將其寫入至cache。
接下來需要判斷要cache的資源是否為 method=GET 且 url包含/static
,原因在於:
- cache只能存放
GET
(如果硬要將POST的資料放入cache也是可以的,但這裡先不介紹)。 /static
是我們編譯完成的靜態檔案的路徑,如果不加此條件那麼所有的GET
都會被加入cache之中 ,會導致cache存放一堆沒用的檔案,例如: 地圖套件的圖資就是GET
的png檔案,這類型的檔案是不需要存在cache中的。
service worker運作流程
當每開啟一次網頁時就會按下面的流程執行:
開啟網頁
-> 註冊service worker
-> install基本資源並啟動新的service worker
-> 判斷版本是否有更新,若有則清除舊的cache
-> 當有request時判斷是否從cache中獲取,若從網路獲取則判斷是否符合存至cache的條件
。
最後
service worker的cache機制確實是可以達到減少網路流量及加快網頁的載入速度,但我認為如果你的網頁不需要離線操作那麼就不需要cache,原因是現今網路速度這麼快的情況下使用者的體感是感覺不出差異的,所以一般情境下單純的service worker就可以了。
若有問題可以留言給我,下次見。