命令式快取指南

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

有些網站可能需要與服務工作人員通訊, 並提供有關結果的通知例如:

  • 網頁將一份網址清單傳送給 Service Worker,前往 預先擷取,因此當使用者點擊 快取中已有文件或網頁子資源的連結 瀏覽起來更加快速
  • 網頁要求 Service Worker 擷取並快取一系列熱門文章, 也能用於離線用途

將這些類型的非重要工作委派給 Service Worker 的好處是,釋出了 。

頁面圖片,要求將資源快取至 Service Worker。

本指南將探討如何實作單向網頁 透過標準瀏覽器 API 和 Workbox 程式庫存取 Service Worker。我們將這些類型稱為 用途命令式快取

正式環境案例

1-800-Flowers.com 透過以下方式,針對服務工作處理程序實作命令式快取 (預先擷取) 開啟 postMessage(),預先擷取 類別頁面中的熱門商品,可以加快後續瀏覽產品詳細資料頁面的速度。

1-800 Flowers 的標誌。

同時,他們會混合使用不同方法來決定要預先擷取哪些項目:

  • 網頁載入時,要求服務工作人員擷取前 9 個項目的 JSON 資料,且 將產生的回應物件新增至快取。
  • 而其餘項目會監聽「mouseover 事件,因此在發生 使用者將遊標移到項目上,即可按「需求」觸發擷取資源的擷取作業。

這些方法會使用 Cache API 來儲存 JSON 回應:

1-800 Flowers 的標誌。
從 1-800Flowers.com 的產品資訊頁面預先擷取 JSON 產品資料。

當使用者點選某個項目時,可以從快取擷取與該項目相關的 JSON 資料。 而無需前往網路,可使瀏覽速度更快。

使用 Workbox

Workbox 可讓您輕鬆傳送訊息至 透過 workbox-window 套件建立一組模組 用在視窗內容中執行是其他 Workbox 套件的輔助工具 這個容器是在 Service Worker 中執行

如要與服務工作人員通訊頁面,請先取得 已註冊的 Service Worker:

const wb = new Workbox('/sw.js');
wb.register();

接著,您就能直接以宣告方式傳送訊息,省去取得 註冊、檢查啟用,或考慮基礎通訊 API:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

Service Worker 會實作 message 處理常式, 聆聽這些訊息您可以選擇傳回回應 非必要:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

使用瀏覽器 API

如果 Workbox 程式庫無法滿足您的需求,您可以按照下列方式實作視窗服務 和工作站通訊。

postMessage API 可用來建立從網頁到服務工作處理程序的單向通訊機制。

網頁呼叫 postMessage() - Service Worker 介面:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

Service Worker 會實作 message 處理常式, 聆聽這些訊息

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

{type : 'MSG_ID'} 屬性不是絕對必要屬性,但是讓網頁 傳送不同類型的指示給 Service Worker (亦即「預先擷取」或「清除」 storage')。服務工作站可以根據此旗標,分支成不同的執行路徑。

如果作業成功,使用者就能享有這項福利,但如果沒有這麼做,主要的使用者流程就不會變更。舉例來說,當 1-800-Flowers.com 嘗試預先快取時,網頁並不需要判斷 Service Worker 是否成功。如果有,使用者將可享有更快速的瀏覽體驗。如果不需要前往新頁面,這需要更多時間。

簡單的預先擷取範例

「命令式快取」最常見的應用方式之一是「預先擷取」,意味著擷取 或是特定網址的資源,以便加快瀏覽速度。

在網站上導入預先擷取的方式有不同:

  • 在網頁中使用「連結預先擷取代碼」:系統會將資源保存在 5 分鐘的瀏覽器快取,之後資源適用的一般 Cache-Control 規則 或
  • 使用服務中的執行階段快取策略,補強前述技巧 工作站,延長預先擷取的生命週期 資源超過這個上限。

針對相對簡單的預先擷取情境,例如預先擷取文件或特定資產 (JS CSS 等)) 執行的技術,就是最適合採用的技術。

如果需要其他邏輯,例如剖析 擷取內部網址,更適合將這項工作完全委派給 Service Worker。

將這些作業類型委派給 Service Worker 有下列優點:

  • 卸載擷取和瀏覽後處理的繁重工作 (即將上線), 延遲載入次要執行緒。如此一來,主執行緒就能處理更重要的工作 像是回應使用者互動之類的工作
  • 讓多個用戶端 (例如分頁) 重複使用共同功能,甚至呼叫 又不封鎖主執行緒。

預先擷取產品詳細資料頁面

首次使用 postMessage(),日期為 Service Worker 介面,並將網址陣列傳送至快取:

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

在 Service Worker 中實作 message 處理常式, 攔截及處理由任何使用中的分頁傳送的訊息:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

在先前的程式碼中,我們導入了名為 fetchAsync() 的小型輔助函式,以便對 網址陣列,並為每個網址發出擷取要求:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

取得回應後,您就可以依賴資源的快取標頭。在許多情況下 但不會快取資源 (就像產品詳細資料頁面一樣), no-cacheCache-control 標頭)。在這些情況下,您可以依據下列條件覆寫這個行為: 將擷取的資源儲存在 Service Worker 快取中。這樣的好處是 以便在離線情況下放送

不只是 JSON 資料

從伺服器端點擷取 JSON 資料後,其中通常包含其他 值得預先擷取的功能,例如與第一層相關的圖像或其他端點資料 資料。

假設在本範例中,傳回的 JSON 資料是雜貨購物網站的資訊:

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

修改 fetchAsync() 程式碼以疊代產品清單,並快取使用者的主頁橫幅 這些原則

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

您可以針對這個程式碼新增一些例外狀況處理,例如 404 錯誤。 但使用 Service Worker 預先擷取的好處是,會失敗且失敗 所發生的情況。您可能也可以在 對預先擷取內容進行後續處理,從而更具彈性,並與所得資料分離 處理和處理資料海闊天空,任您發揮。

結論

在本文中,我們介紹了頁面和服務之間「單向」通訊的常見用途。 工作站:命令式快取。本文討論的範例僅供示範一種 這種模式也能應用在其他用途上,例如 視需求快取熱門文章,以便離線閱讀、將文章加入書籤等。

如需更多網頁和服務工作處理程序的通訊模式,請參閱:

  • 廣播更新:向服務工作人員呼叫網頁通知 查看重要更新 (例如有新版網頁應用程式可用)。
  • 雙向通訊:將工作委派給 Service Worker (例如 可大幅加快下載速度),並隨時透過頁面瞭解進度。