背景同步簡介

Jake Archibald
Jake Archibald

背景同步處理是新的網路 API,可讓您在使用者連線穩定前,暫緩執行動作。這可確保使用者要傳送的內容確實傳送出去。

問題

網際網路是浪費時間的好地方。我們不會浪費時間在網路上搜尋,貓咪不喜歡花朵變色龍喜歡泡泡,或是Eric Bidelman90 年代末的推桿高爾夫英雄

但有時候,我們並不打算浪費時間。理想的使用者體驗應類似於:

  1. 手機從口袋中拿出。
  2. 達成小目標。
  3. 手機放回口袋。
  4. 繼續生活。

不幸的是,這項體驗經常因連線不佳而中斷。我們都曾經歷過這種情況。你盯著空白畫面或旋轉圖示,知道應該放棄並繼續生活,但還是再等 10 秒,以防萬一。10 秒過後,不會發生任何事情。

但為何要放棄?你已經花費時間,如果什麼都沒有就離開,那就太浪費了,因此你決定繼續等待。到這個時候,你「想」放棄,但你知道,只要你放棄,一切就會回到原點,因為如果只是等待,所有內容都會載入。

服務工作者可解決網頁載入問題,讓您從快取提供內容。但如果網頁需要傳送內容給伺服器,該怎麼辦呢?

目前,如果使用者按下訊息的「傳送」按鈕,就必須一直盯著旋轉圖示,直到傳送作業完成為止。如果使用者嘗試離開或關閉分頁,我們會使用 onbeforeunload 顯示類似「不,我需要你再盯著這個旋轉圖示看一會兒」的訊息。抱歉」如果使用者沒有連線,我們會告訴使用者:「很抱歉,必須稍後再試一次。」

這太爛了。背景同步處理功能可讓您更有效率。

解決方案

以下影片是 Emojoy (僅限表情符號的即時通訊示範)。這是一個漸進式網頁應用程式,採用離線優先的運作方式。應用程式會使用推播訊息和通知,並使用背景同步功能。

如果使用者在沒有連線的情況下嘗試傳送訊息,系統會在使用者連上網路後在背景傳送訊息。

自 2016 年 3 月起,Chrome 已支援背景同步處理 49 以上版本。按照下列步驟操作,即可查看相關動作:

  1. 開啟 Emojoy
  2. 離線 (使用飛航模式或前往當地的法拉第籠)。
  3. 輸入訊息。
  4. 返回主畫面 (可選擇關閉分頁或瀏覽器)。
  5. 連上網路。
  6. 訊息會在背景傳送!

能夠像這樣在背景傳送,可進一步提升效能。應用程式不需要特別處理訊息傳送作業,因此可以立即將訊息加入輸出內容。

如何要求背景同步

在真正的可擴充網頁樣式中,這是一項低階功能,可讓您自由執行所需的操作。您會要求在使用者連線時觸發事件。如果使用者已連線,事件就會立即生效。接著,您可以監聽該事件,並執行所需的操作。

與推播訊息一樣,這項功能會使用 Service Worker 做為事件目標,讓這項功能在網頁未開啟時運作。如要開始,請透過網頁註冊同步處理:

// Register your service worker:
navigator.serviceWorker.register('/sw.js');

// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});
 ```

Then listen for the event in `/sw.js`:

```js
self.addEventListener('sync', function(event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

大功告成!在上述情況中,doSomeStuff() 應傳回承諾,指出嘗試執行的動作是否成功/失敗。如果傳回承諾,表示同步處理已完成。如果失敗,系統會安排另一次同步作業,以便重試。重試同步作業也會等待連線,並採用指數輪詢。

每次同步處理時,同步處理作業的代碼名稱 (上述範例中的「myFirstSync」) 不得重複。如果您註冊同步處理時使用了與待處理的同步處理作業相同的代碼,則該代碼會與現有的同步作業合併。也就是說,您可以為每次使用者傳送郵件註冊「清空收件匣」同步作業,但如果使用者在離線時傳送 5 封郵件,您只會在他們上線時收到一次同步作業。如要使用 5 個不同的同步處理事件,請使用不重複的代碼!

以下是簡單的示範,只會執行最基本的工作,使用同步處理事件顯示通知。

我可以將背景同步處理功能用於哪些用途?

在理想情況下,您可以使用這項功能,將重要資料排定在網頁生命週期以外的時間。即時通訊訊息、電子郵件、文件更新、設定變更、相片上傳... 所有您想傳送至伺服器的內容 (即便使用者離開或關閉分頁)。網頁可將這些內容儲存在 indexedDB 中的「outbox」儲存空間,Service Worker 會擷取並傳送這些內容。

不過,您也可以使用它擷取少量資料...

另一個示範!

這是我為超級充電網頁載入建立的離線維基百科示範。我已在其中加入一些背景同步功能。

親自試試看。請確認你使用的是 Chrome 49 以上版本,然後執行下列操作:

  1. 前往任一文章 (可能是 Chrome)。
  2. 處於離線狀態 (使用飛航模式,或是加入像我一樣可靠的行動服務供應商)。
  3. 按一下其他文章的連結。
  4. 您應該已經收到無法載入網頁的通知;如果網頁只載入一段時間,也會出現。
  5. 同意接收通知。
  6. 關閉瀏覽器。
  7. 切換為線上狀態
  8. 系統會在文章下載完畢、快取完成且可供查看時通知你!

使用者只要採用這個模式,就能將手機放入口袋,繼續過著自己的生活,因為他們知道手機會在擷取所需內容時發出通知。

權限

我展示的示範使用 網頁通知,需要權限,但背景同步本身不需要。

同步處理事件通常會在使用者開啟網站時完成,因此需要使用者授權才會對體驗造成負面影響。我們會限制同步作業的註冊和觸發時間,以防濫用。例如:

  • 只有在使用者開啟網站視窗時,您才能註冊同步處理事件。
  • 事件執行時間有上限,因此您無法使用這些事件每隔 x 秒對伺服器執行 ping 作業、挖掘比特幣或執行其他作業。

當然,這些限制可能會因實際使用情況而變鬆或緊縮。

漸進增強

所有瀏覽器均不支援背景同步功能,特別是 Safari 和 Edge 尚未支援 Service Worker。不過,漸進式改善功能在這裡很有幫助:

if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(function(reg) {
    return reg.sync.register('tag-name');
  }).catch(function() {
    // system was unable to register for a sync,
    // this could be an OS-level restriction
    postDataFromThePage();
  });
} else {
  // serviceworker/sync not supported
  postDataFromThePage();
}

如果無法使用服務工作者或背景同步功能,請按照目前的方式,從網頁發布內容。

即便使用者看來連線狀況良好,也建議您使用背景同步功能。這樣一來,即使在資料傳送過程中,使用者遇到瀏覽及關閉分頁的情形,也還是能使用背景同步處理功能。

未來

我們預計在 2016 上半年將背景同步功能納入穩定版 Chrome,同時開發「定期背景同步」的變化版本。透過定期背景同步處理功能,您可以要求以時間間隔、電池狀態和網路狀態為限制的事件。當然,這需要使用者授權,且瀏覽器也會決定這些事件的觸發時機和頻率。換句話說,新聞網站可以每小時要求同步處理一次,但瀏覽器可能會知道您在 07:00 時只讀取該網站,因此同步處理作業每天會在 06:50 啟動。比起一次性同步,這個做法有點進步,但很快就會推出。

我們會逐步將 Android 和 iOS 的成功模式導入網頁,同時保留網頁的優點!