Progressive Web Apps 的一個重要面向是,其穩定性;因此,即使網路狀況不佳,也能快速載入素材資源、持續吸引使用者互動並提供意見回饋。怎麼會這樣?感謝 Service Worker fetch
事件。
擷取事件
fetch
事件可讓我們攔截 PWA 在 Service Worker 範圍內發出的所有網路要求,包含相同來源和跨來源的要求。除了導覽和資產要求外,如果從已安裝的 Service Worker 擷取網頁,那麼在網站初次載入後不需透過網路呼叫轉譯網頁。
fetch
處理常式會接收來自應用程式的所有要求,包括網址和 HTTP 標頭,然後讓應用程式開發人員決定如何處理這些要求。
您的服務工作處理程序可以將要求轉送至網路、以先前快取的回應做為回應,或是建立新回應。選擇權完全操之在您。 以下提供一個簡單的範例:
self.addEventListener("fetch", event => {
console.log(`URL requested: ${event.request.url}`);
});
回應要求
收到要求傳入 Service Worker 時,你可以採取以下兩種做法:您可以忽略它讓它進入網路,或對其進行回應。您可以從 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()
,後者會使用回應來解決。
建立回應
有了 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 回應。 請使用快取儲存空間介面將資產儲存在裝置上。
您可以使用 Cache Storage API,檢查從 PWA 接收的要求是否出現在快取中,如果如果是的話,則會回應 respondWith()
。
做法是先搜尋快取,頂層 caches
介面提供的 match()
函式會搜尋來源或單一開啟的快取物件中的所有商店。
match()
函式接收 HTTP 要求或網址做為引數,並傳回依據與對應鍵相關聯的回應解析的承諾。
// 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
,並透過規則運算式或網址格式剖析。(在本文撰寫期間,並非所有平台都支援網址格式)。
最常見的策略如下:
- 先快取
- 先搜尋快取回應,如果找不到,就會回到網路。
- 聯播網優先
- 會先要求網路的回應,如果系統未傳回任何回應,請在快取中檢查回應。
- 重新驗證時過時
- 從快取提供回應,在背景中要求最新版本,並將其儲存至快取,以供下次要求素材資源時參考。
- 僅限網路
- 一律回覆網路的回應或發生錯誤。系統一律不會參考快取資料。
- 僅限快取
- 一律回應快取或錯誤的回應。網路一律不會獲得諮詢必須將採用這項策略提供的資產加入快取,才能收到要求。
先快取
採用這項策略,Service Worker 會在快取中尋找相符的要求,如果快取成功,就會傳回對應的 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 要求等資源來說非常實用。
僅快取
僅快取策略可確保要求一律不會傳送至網路。所有傳入的要求都會以預先填入的快取項目回應。以下程式碼使用 fetch
事件處理常式與快取儲存空間的 match
方法,僅回應快取:
self.addEventListener("fetch", event => {
event.respondWith(caches.match(event.request));
});
自訂策略
雖然上述是常見的快取策略,但您必須負責管理服務工作處理程序以及要求的處理方式。如果以上方法都不符合您的需求,您可以自行建立。
舉例來說,您可以使用設有逾時時間的網路優先策略,優先更新更新內容,但前提是回應內容必須在您設定的門檻內。您也可以合併快取的回應與網路回應,然後從 Service Worker 建構複雜的回應。
正在更新資產
持續更新 PWA 的快取資產並不容易。雖然過時的策略在重新驗證策略只是其中一種做法,但這不是唯一的做法。在「更新章節」中,您將瞭解各種必要技巧,確保應用程式的內容和資產隨時保持最新狀態。