漸進式網路應用程式的重要特點是可靠性,即使網路連線品質不佳,也能快速載入資產,讓使用者保持參與度並立即獲得回饋。這怎麼可能?這要歸功於 Service Worker fetch
事件。
擷取事件
透過 fetch
事件,我們可以攔截 PWA 在 Service Worker 範圍內發出的每個網路要求,包括同源和跨來源要求。除了導覽和資產要求,從已安裝的 Service Worker 擷取資料,也能讓網站在首次載入後,無須發出網路呼叫即可算繪網頁瀏覽。
fetch
處理常式會接收應用程式的所有要求,包括網址和 HTTP 標頭,並讓應用程式開發人員決定如何處理這些要求。
Service Worker 可以將要求轉送至網路、使用先前快取的回應來回應,或建立新的回應。一切由你決定。 簡單範例如下:
self.addEventListener("fetch", event => { console.log(`URL requested: ${event.request.url}`); });
回覆要求
當服務工作人員收到要求時,您可以選擇忽略要求 (讓要求傳送至網路),也可以選擇回應要求。在 Service Worker 中回應要求,即可選擇要將哪些內容傳回 PWA,以及傳回方式,即使使用者處於離線狀態也沒問題。
如要回應傳入的要求,請在 fetch
事件處理常式中呼叫 event.respondWith()
,如下所示:
// fetch event handler in your service worker file self.addEventListener("fetch", event => { const response = .... // a response or a Promise of response event.respondWith(response); });
您必須同步呼叫 respondWith()
,並傳回 Response 物件。不過,您無法在擷取事件處理常式完成後呼叫 respondWith()
,例如在非同步呼叫中。如需等待完整的回應,可以將 Promise 傳遞至 respondWith()
,並以 Response 解析。
建立回覆
有了 Fetch API,您可以在 JavaScript 程式碼中建立 HTTP 回應,這些回覆可使用 Cache Storage API 進行快取,並以來自網頁伺服器的形式傳回。
如要建立回應,請建立新的 Response
物件,並設定其內文和選項,例如狀態和標頭:
const simpleResponse = new Response("Body of the HTTP response"); const options = { status: 200, headers: { 'Content-type': 'text/html' } }; const htmlResponse = new Response("<b>HTML</b> content", options)
從快取回應
您已瞭解如何從 Service Worker 提供 HTTP 回應,現在可以使用 Caching Storage 介面,將資產儲存在裝置上。
您可以使用快取儲存空間 API 檢查快取中是否有 PWA 傳送的要求,如果有的話,就以該要求回應 respondWith()
。 如要這麼做,請先在快取中搜尋。頂層 caches
介面提供的 match()
函式會搜尋來源中的所有商店,或搜尋單一開啟的快取物件。
match()
函式會接收 HTTP 要求或網址做為引數,並傳回 Promise,該 Promise 會以與對應鍵相關聯的 Response 解決。
// Global search on all caches in the current origin caches.match(urlOrRequest).then(response => { console.log(response ? response : "It's not in the cache"); }); // Cache-specific search caches.open("pwa-assets").then(cache => { cache.match(urlOrRequest).then(response => { console.log(response ? response : "It's not in the cache"); }); });
快取策略
只從瀏覽器快取提供檔案,並不適用於所有用途。舉例來說,使用者或瀏覽器可以清除快取。因此,您應自行定義策略,為 PWA 提供資產。您不限於使用一種快取策略。您可以為不同的網址模式定義不同的變數。舉例來說,您可以為最低 UI 資產制定一項策略,為 API 呼叫制定另一項策略,並為圖片和資料網址制定第三項策略。 如要這麼做,請在 ServiceWorkerGlobalScope.onfetch
中讀取 event.request.url
,並透過規則運算式或 URL 模式剖析。(撰寫本文時,並非所有平台都支援網址模式)。
最常見的策略包括:
- 快取優先
- 先搜尋快取的回應,如果找不到,則會改用網路。
- 電視網優先
- 先向網路要求回應,如果沒有傳回任何內容,則檢查快取中的回應。
- 網頁無回應時顯示過時內容
- 從快取提供回應,同時在背景要求最新版本,並儲存至快取,以供下次要求資產時使用。
- 僅限聯播網
- 一律會回覆網路的回應或錯誤。系統絕不會查詢快取。
- 僅限快取
- 一律會回覆快取中的回應或錯誤。系統絕不會諮詢該網路。使用這項策略放送的資產必須先加入快取,才能提出要求。
先快取
使用這項策略時,服務工作人員會在快取中尋找相符的要求,並在快取中找到對應的 Response 時傳回該 Response。否則會從網路擷取回應 (視需要更新快取,以供日後呼叫)。如果沒有快取回應或網路回應,要求就會發生錯誤。由於不需連上網路即可放送素材資源,速度通常較快,因此這項策略會優先考量成效,而非即時性。
self.addEventListener("fetch", event => { event.respondWith( caches.match(event.request) .then(cachedResponse => { // It can update the cache to serve updated content on the next request return cachedResponse || fetch(event.request); } ) ) });
網路優先
這項策略與「快取優先」策略相反,會檢查是否可透過網路滿足要求,如果無法,則嘗試從快取擷取要求。例如「先快取」。如果沒有網路回應或快取回應,要求就會發生錯誤。從網路取得回應通常比從快取取得回應慢,因此這項策略會優先處理更新內容,而非效能。
self.addEventListener("fetch", event => { event.respondWith( fetch(event.request) .catch(error => { return caches.match(event.request) ; }) ); });
網頁無回應時顯示過時內容
「過時後重新驗證」策略會立即傳回快取的回應,然後檢查網路是否有更新,並在找到更新時取代快取的回應。這項策略一律會發出網路要求,因為即使找到快取資源,系統也會嘗試使用從網路收到的內容更新快取中的內容,以便在下一個要求中使用更新後的版本。因此,這項策略可讓您享有快取優先策略的快速服務,並在背景更新快取。
self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(cachedResponse => { const networkFetch = fetch(event.request).then(response => { // update the cache with a clone of the network response const responseClone = response.clone() caches.open(url.searchParams.get('name')).then(cache => { cache.put(event.request, responseClone) }) return response }).catch(function (reason) { console.error('ServiceWorker fetch failed: ', reason) }) // prioritize cached response over network return cachedResponse || networkFetch } ) ) })
僅限網路
「僅限網路」策略與瀏覽器在沒有 Service Worker 或 Cache Storage API 時的行為類似。只有在可從網路擷取資源時,要求才會傳回資源。這通常適用於僅限線上的 API 要求等資源。
僅限快取
「僅限快取」策略可確保要求絕不會傳送至網路,所有傳入的要求都會以預先填入的快取項目回應。下列程式碼會搭配快取儲存空間的 match
方法使用 fetch
事件處理常式,只回應快取:
self.addEventListener("fetch", event => { event.respondWith(caches.match(event.request)); });
自訂策略
雖然上述是常見的快取策略,但您仍須負責服務工作人員和要求的處理方式。如果這些都不符合需求,請自行建立。
舉例來說,您可以搭配逾時使用「網路優先」策略,優先處理更新內容,但前提是回應必須在您設定的門檻內出現。您也可以將快取回應與網路回應合併,並從 Service Worker 建構複雜的回應。
更新資產
讓 PWA 的快取資產保持在最新狀態可能很困難。雖然「過時重新驗證」策略是其中一種做法,但並非唯一方法。在更新章節中,您將學到各種技巧,確保應用程式的內容和資產保持在最新狀態。