背景擷取功能簡介

Jake Archibald
Jake Archibald

我們在 2015 年推出背景同步處理功能,讓 Service Worker 會將工作延遲到使用者有連線為止。這表示使用者可以輸入 訊息、按下傳送後離開網站,也知道訊息將立即傳送或 具備網路連線

它是很實用的功能,但會要求 Service Worker 在 擷取。這並不是發送訊息之類的短時間問題,但如果工作需要 瀏覽器太久會終止 Service Worker,否則會危及使用者隱私, 電池。

比方說,如果你需要下載 需要較長時間的項目 (例如電影、Podcast 或 Podcast) 遊戲關卡這就是背景擷取功能的用途。

自 Chrome 74 版起,系統預設提供背景擷取功能。

下面是兩分鐘的簡短示範,說明比較傳統操作方式和背景擷取功能使用的狀態:

親自體驗功能瀏覽程式碼

運作方式

背景擷取的運作方式如下:

  1. 指示瀏覽器在背景執行一組擷取作業,
  2. 瀏覽器會擷取這些資料,並向使用者顯示進度。
  3. 擷取完成或失敗時,瀏覽器會開啟 Service Worker 並觸發事件。 顯示出了什麼事您可以在此決定如何處理回應 (如果有的話)。

如果使用者執行步驟 1 之後關閉網頁,系統便不會繼續下載。由於 擷取結果非常顯眼且容易取消,使用者不必擔心會遇到隱私權問題 背景同步處理任務由於 Service Worker 不會持續執行,因此不必擔心 它可能會濫用系統,例如在背景挖掘比特幣。

在某些平台上 (例如 Android),瀏覽器在步驟 1 之後可能會關閉,因為 瀏覽器可以將擷取內容傳送至作業系統。

如果使用者在離線狀態下啟動下載程序,或在下載期間離線,應用程式會在背景執行 擷取作業將暫停並在稍後繼續。

API

特徵偵測

和任何新功能一樣,您想要偵測瀏覽器是否支援此功能。在背景擷取中 例如:

if ('BackgroundFetchManager' in self) {
  // This browser supports Background Fetch!
}

開始背景擷取作業

主要 API 會停止 Service Worker 註冊, 因此,請務必先註冊 Service Worker。然後執行下列步驟:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
    title: 'Episode 5: Interesting things.',
    icons: [{
      sizes: '300x300',
      src: '/ep-5-icon.png',
      type: 'image/png',
    }],
    downloadTotal: 60 * 1024 * 1024,
  });
});

backgroundFetch.fetch 會使用三個引數:

參數
id string
可用於辨識這項背景擷取作業。

如果 ID 與現有背景相符,「backgroundFetch.fetch」就會拒絕 擷取。

requests Array<Request|string>
要擷取的內容。系統會將字串視為網址,然後轉換成 透過 new Request(theString) 產生 Request

只要資源允許透過 CORS

注意:Chrome 目前不支援會 需要 CORS 預檢

options 物件,可包含以下內容:
options.title string
要顯示的瀏覽器標題與進度。
options.icons Array<IconDefinition>
包含 `src`、`size` 和 `type` 的物件陣列。
options.downloadTotal number
回應主體的總大小 (解壓縮後 gzip 檔案)。

雖然這不是必要步驟,但我們強烈建議你提供這項資訊。可用來 並告知下載大小並提供進度資訊。如未提供 瀏覽器會告訴使用者尺寸不明,因此使用者 取消下載的可能性

如果背景擷取下載次數超過這裡指定的數量,系統就會取消擷取。是 若下載內容小於 downloadTotal 也沒有問題,因此如果沒有 因此請謹慎考慮,盡可能提高下載內容總數。

backgroundFetch.fetch 會傳回以 BackgroundFetchRegistration 解析的承諾。我會 稍後會詳細說明承諾使用者已選擇停止下載 提供的參數無效。

為單一背景擷取提供多個要求,您就能將具有邏輯意義的資料結合在一起 單一用途例如,一部電影可以分割成 1000 多的資源 ( MPEG-DASH), 並提供更多資源,例如圖片遊戲的關卡可以分散在 JavaScript、圖片和音訊資源。但對使用者來說,可能只有「電影」或「關卡」。

取得現有的背景擷取作業

您可以取得現有的背景擷取作業,如下所示:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

...傳送所需背景擷取的 id。如果沒有,get 會傳回 undefined 並搭配該 ID 的有效背景擷取

背景擷取視為「已啟用」從註冊算起到成功 作業失敗或遭到取消

您可以使用 getIds 取得所有正在執行的背景擷取作業清單:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

背景擷取註冊

BackgroundFetchRegistration (上述範例中的 bgFetch) 包含下列內容:

屬性
id string
背景擷取的 ID。
uploadTotal number
要傳送至伺服器的位元組數,
uploaded number
成功傳送的位元組數。
downloadTotal number
在登錄背景擷取作業時提供的值;或 零時差弱點
downloaded number
成功接收的位元組數。

這個值可能會減少。舉例來說,如果連線中斷且無法下載 如果已恢復,瀏覽器就會重新開始擷取該資源的擷取作業。

result

可以是下列其中一項:

  • "":已啟用背景擷取功能,因此尚無結果。
  • "success":已成功擷取背景。
  • "failure":無法擷取背景。這個值只會在 背景擷取就會完全失敗,因為瀏覽器無法重試/繼續。
failureReason

可以是下列其中一項:

  • "":背景擷取失敗。
  • "aborted":使用者已取消背景擷取作業,或 已呼叫 abort()
  • "bad-status":其中一個回應的狀態不正確,例如404。
  • "fetch-error":其中一個擷取作業基於其他原因失敗,例如 CORS、MIX、部分回應無效,或是擷取作業的一般網路失敗 無法重試。
  • "quota-exceeded" - 已在背景執行的儲存空間配額 擷取。
  • "download-total-exceeded" - 提供的「downloadTotal」之前為 。
recordsAvailable boolean
可以存取基礎要求/回應嗎?

設為 false 後,就無法使用 matchmatchAll

方法
abort() 傳回 Promise<boolean>
取消背景擷取作業。

如果成功取消擷取,傳回的承諾會以 true 解析。

matchAll(request, opts) 傳回 Promise<Array<BackgroundFetchRecord>>
取得要求 和回應

這裡的引數與 快取 API。如果呼叫不含引數,系統會傳回所有記錄的承諾。

詳情請見下面的說明。

match(request, opts) 傳回 Promise<BackgroundFetchRecord>
如上所述,但會以 第一個相符項目
活動
progress 觸發時機為任何 uploadeddownloadedresultfailureReason變更。

追蹤進度

可以透過 progress 事件達成。請注意,downloadTotal 是您 如未提供值,則傳回 0

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;

  const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
  console.log(`Download progress: ${percent}%`);
});

取得要求與回應

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

recordBackgroundFetchRecord,如下所示:

屬性
request Request
提供的要求。
responseReady Promise<Response>
擷取的回應。

對方可能尚未收到回覆,但保證不會收到回覆。承諾 就會拒絕。

Service Worker 事件

活動
backgroundfetchsuccess 已成功擷取所有內容。
backgroundfetchfailure 一或多項擷取作業失敗。
backgroundfetchabort 一或多項擷取作業失敗。

如果您想清除相關資料,這個方法就相當實用。

backgroundfetchclick 使用者點選下載進度使用者介面。

事件物件包含下列內容:

屬性
registration BackgroundFetchRegistration
方法
updateUI({ title, icons }) 變更原先設定的標題/圖示。這不是必要步驟,但可以讓您 視需要提供更多背景資訊您在訂閱期間只能執行「一次」操作 backgroundfetchsuccessbackgroundfetchfailure 事件。

回應成功/失敗

我們看過 progress 事件,但這只會在使用者開啟網頁時派上用場 你的網站背景擷取的主要優點是在使用者離開 或關閉瀏覽器

如果背景擷取成功完成,服務工作處理程序就會收到 backgroundfetchsuccess 事件和 event.registration 將是背景擷取註冊。

在這個事件過後,擷取的要求和回應就無法再存取,因此如果您想 請將其移至 Cache API 之類的位置。

與大部分的 Service Worker 事件一樣,請使用 event.waitUntil,讓 Service Worker 知道事件 。

例如在 Service Worker 中:

addEventListener('backgroundfetchsuccess', (event) => {
  const bgFetch = event.registration;

  event.waitUntil(async function() {
    // Create/open a cache.
    const cache = await caches.open('downloads');
    // Get all the records.
    const records = await bgFetch.matchAll();
    // Copy each request/response across.
    const promises = records.map(async (record) => {
      const response = await record.responseReady;
      await cache.put(record.request, response);
    });

    // Wait for the copying to complete.
    await Promise.all(promises);

    // Update the progress notification.
    event.updateUI({ title: 'Episode 5 ready to listen!' });
  }());
});

失敗可能就是單一的 404,但這可能並不重要,因此 仍值得您按照上述方式將部分回應複製到快取中。

回應點擊

顯示下載進度和結果的使用者介面可供點選。以下位置中的 backgroundfetchclick 事件: Service Worker 可讓您回應此事與 event.registration 以上一樣將為背景 擷取註冊資料。

此事件的常見用途為開啟視窗:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

其他資源

修正內容:本文先前的版本誤將背景擷取功能稱為「網路標準」。這個 API 目前未採用標準測試群組,如需草稿社群報告,請前往 WICG 參閱相關規格