漸進式網路應用程式的主要特色是可靠,可快速載入素材資源,讓使用者保持互動,並在連線品質不佳的情況下立即提供意見回饋。怎麼可能?感謝服務工作程式 fetch
事件。
fetch 事件
fetch
事件可讓我們攔截 PWA 在服務工作者範圍內發出的每個網路要求,包括同源和跨來源要求。除了導覽和素材資源要求之外,從已安裝的服務工作者擷取資料,可讓網站首次載入後的網頁瀏覽作業,在無網路呼叫的情況下呈現。
fetch
處理常式會接收來自應用程式的所有要求,包括網址和 HTTP 標頭,並讓應用程式開發人員決定如何處理這些要求。
Service Worker 可以將要求轉送至網路、回應先前快取的回應,或建立新的回應。一切由你決定。以下提供一個簡單的範例:
self.addEventListener("fetch", event => {
console.log(`URL requested: ${event.request.url}`);
});
回應要求
當要求傳送至服務工作者時,您可以採取兩種做法:忽略要求 (讓要求傳送至網路) 或回應要求。您可以透過服務工作者回應要求,選擇要傳回哪些內容,以及傳回方式 (即使使用者處於離線狀態也一樣)。
如要回應傳入的要求,請在 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)
從快取回應
您已瞭解如何透過服務工作者提供 HTTP 回應,現在是時候使用快取儲存空間介面,在裝置上儲存資產了。
您可以使用快取儲存空間 API 檢查從 PWA 收到的要求是否可在快取中使用,如果可以,請使用該要求回應 respondWith()
。為此,您必須先在快取中搜尋。match()
函式可在頂層 caches
介面中使用,用於搜尋來源或單一已開啟快取物件的所有商店。
match()
函式會接收 HTTP 要求或網址做為引數,並傳回 Promise,該 Promise 會解析與對應鍵相關聯的回應。
// 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
,並透過規則運算式或網址模式進行剖析。(在撰寫本文時,並非所有平台都支援網址模式)。
最常見的策略如下:
- 先快取
- 首先搜尋快取的回應,如果找不到,就改為使用網路。
- 聯播網優先
- 首先要求網路回應,如果沒有傳回任何回應,則檢查快取中的回應。
- 重新驗證時過時
- 在背景要求最新版本並將其儲存至快取,以便在下次要求素材資源時使用。
- 僅限網路
- 一律會傳回網路的回應或錯誤。系統不會查詢快取。
- 僅快取
- 一律會回覆快取中的回應或錯誤。我們絕不會向網路查詢。使用此策略提供的素材資源必須先加入快取,才能供使用者要求。
先快取
採用這項策略後,服務工作者會在快取中尋找相符的要求,並在快取到對應的回應時傳回。否則,它會從網路擷取回應 (可選,為日後的呼叫更新快取)。如果沒有快取回應或網路回應,要求就會發生錯誤。由於不經過網路就能放送素材資源的速度通常較快,因此這項策略會優先考量成效,而非新鮮度。
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) ;
})
);
});
重新驗證時過時
Stale while revalidate 策略會立即傳回快取的回應,然後檢查網路是否有更新,並在找到更新時取代快取的回應。這個策略一律會發出網路要求,因為即使找到快取的資源,也會嘗試使用從網路收到的內容更新快取中的內容,以便在下次要求中使用更新後的版本。因此,這項策略可讓您快速提供快取優先策略,並在背景更新快取。
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));
});
自訂策略
雖然上述是常見的快取策略,但您仍需負責服務工作者和要求的處理方式。如果上述方法都不符合您的需求,請自行建立。
舉例來說,您可以使用網路優先策略搭配逾時機制,為更新內容設定優先順序,但只有在回應出現在您設定的門檻內時才會執行。您也可以將快取的回應與網路回應合併,並透過服務工作者建立複雜的回應。
更新素材資源
維持 PWA 快取素材資源的最新狀態可能會相當困難。雖然「Stale while revalidate」策略是一種做法,但並非唯一做法。在「更新章節」中,您將學習各種技巧,以便持續更新應用程式的內容和資產。