當您將資料傳送至網路伺服器時,有時要求將會失敗。這可能是因為使用者已中斷連線,或是伺服器停止運作。無論是您經常要嘗試再次傳送要求,都不成問題。
新的 BackgroundSync API 是解決這個問題的理想解決方案。Service Worker 偵測到網路要求失敗時,可註冊接收 sync
事件,當瀏覽器認為連線已傳回時,就會傳送事件。請注意,即便使用者已離開應用程式,也可以傳送同步處理事件,這樣比重試失敗要求的傳統方法有效。
Workbox Background Sync 的目標是更容易使用 BackgroundSync API,並與其他 Workbox 模組整合。並針對尚未實作 BackgroundSync 的瀏覽器導入備用策略。
支援 BackgroundSync API 的瀏覽器會由瀏覽器管理的間隔代您自動重播失敗的要求,可能在嘗試重播之間採用指數輪詢策略。在不支援 BackgroundSync API 的瀏覽器中,Workbox Background Sync 會在服務工作站啟動時自動嘗試重播。
基本用法
使用 Background Sync 時,最簡單的方法是使用 Plugin
,將失敗的要求自動排入佇列,並在日後觸發 sync
事件時重試。
import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';
const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});
registerRoute(
/\/api\/.*\/*.json/,
new NetworkOnly({
plugins: [bgSyncPlugin],
}),
'POST'
);
BackgroundSyncPlugin
會掛鉤 fetchDidFail
外掛程式回呼,而 fetchDidFail
只會在發生例外狀況時叫用,很可能是網路故障。也就是說,如果收到的回應具有 4xx
或 5xx
錯誤狀態,系統就不會重試要求。如要重試所有產生的要求 (例如 5xx
狀態),您可以在策略中新增 fetchDidSucceed
外掛程式。
const statusPlugin = {
fetchDidSucceed: ({response}) => {
if (response.status >= 500) {
// Throwing anything here will trigger fetchDidFail.
throw new Error('Server error.');
}
// If it's not 5xx, use the response as-is.
return response;
},
};
// Add statusPlugin to the plugins array in your strategy.
進階用法
Workbox Background Sync 也提供 Queue
類別,讓您執行個體化和新增失敗的要求。失敗的要求會儲存在 IndexedDB 中,如果瀏覽器認為連線恢復 (也就是收到同步事件時),就會重試。
建立佇列
如要建立 Workbox 背景同步佇列,您必須使用佇列名稱建構這個佇列 (此佇列不得在您的來源中具有唯一性):
import {Queue} from 'workbox-background-sync';
const queue = new Queue('myQueueName');
佇列名稱會做為標記名稱的一部分,由全域 SyncManager
比對 register()
。同時也是索引資料庫資料庫的物件存放區名稱。
將要求新增至佇列
建立佇列執行個體後,您可以為該執行個體新增失敗的要求,您可以透過叫用 .pushRequest()
方法新增失敗的要求。舉例來說,以下程式碼會擷取任何失敗的要求並新增至佇列:
import {Queue} from 'workbox-background-sync';
const queue = new Queue('myQueueName');
self.addEventListener('fetch', event => {
// Add in your own criteria here to return early if this
// isn't a request that should use background sync.
if (event.request.method !== 'POST') {
return;
}
const bgSyncLogic = async () => {
try {
const response = await fetch(event.request.clone());
return response;
} catch (error) {
await queue.pushRequest({request: event.request});
return error;
}
};
event.respondWith(bgSyncLogic());
});
將連線新增至佇列後,服務工作站收到 sync
事件 (當瀏覽器認為連線已恢復時) 時,就會自動重試要求。不支援 BackgroundSync API 的瀏覽器會在每次啟動服務工作站時重試佇列。這項操作需要使用控管服務工作站的頁面,因此不太有效。
測試 Workbox 背景同步處理
很抱歉,測試 BackgroundSync 的原因有很多種。
如要測試導入作業,建議您執行下列操作:
- 載入頁面並註冊 Service Worker。
- 關閉電腦的網路或關閉網路伺服器。
- 請勿使用 CHROME DEVTOOLS 離線工具。開發人員工具中的離線核取方塊只會影響來自網頁的要求。Service Worker 要求會繼續傳送。
- 發出在 Workbox Background Sync 中排入佇列的網路要求。
- 如要查看要求已排入佇列,請查看
Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
- 如要查看要求已排入佇列,請查看
- 開啟你的網路或網路伺服器。
強制執行早期
sync
事件,方法是前往Chrome DevTools > Application > Service Workers
,輸入workbox-background-sync:<your queue name>
的標記名稱,其中<your queue name>
應為您設定的佇列名稱,然後按一下「Sync」按鈕。對於失敗的要求,您應該會看到網路要求成功通過,而 IndexedDB 資料現在應該是空白的,因為要求已成功重新播放。
類型
BackgroundSyncPlugin
實作 fetchDidFail
生命週期回呼的類別。這樣就能更輕鬆地將失敗的要求新增至背景同步佇列。
屬性
-
建構函式
void
constructor
函式如下所示:(name: string, options?: QueueOptions) => {...}
-
名稱
字串
如需參數詳細資料,請參閱
workbox-background-sync.Queue
說明文件。 -
選項
QueueOptions 選用
-
returns
-
Queue
用於管理在 IndexedDB 中儲存失敗要求的類別,並於稍後重試。所有儲存及重播程序都可以透過回呼觀測。
屬性
-
建構函式
void
使用指定的選項建立佇列的執行個體
constructor
函式如下所示:(name: string, options?: QueueOptions) => {...}
-
名稱
字串
這個佇列的專屬名稱。此名稱不得重複,因為此名稱是用來註冊同步事件,以及將要求儲存在這個執行個體專屬的索引資料庫。如果偵測到重複的名稱,就會擲回錯誤。
-
選項
QueueOptions 選用
-
returns
-
-
名稱
字串
-
getAll
void
按
maxRetentionTime
傳回所有未過期的項目。任何過期的項目都會從佇列中移除。getAll
函式如下所示:() => {...}
-
returns
Promise<QueueEntry[]>
-
-
popRequest
void
移除並傳回佇列中的最後一個要求 (以及要求的時間戳記和任何中繼資料)。傳回的物件格式為:
{request, timestamp, metadata}
。popRequest
函式如下所示:() => {...}
-
returns
Promise<QueueEntry>
-
-
pushRequest
void
將傳遞的要求儲存在佇列結尾的 IndexedDB 中 (含時間戳記和任何中繼資料)。
pushRequest
函式如下所示:(entry: QueueEntry) => {...}
-
項目
QueueEntry
-
returns
Promise<void>
-
-
registerSync
void
使用這個執行個體專屬的代碼註冊同步處理事件。
registerSync
函式如下所示:() => {...}
-
returns
Promise<void>
-
-
replayRequests
void
循環處理佇列中的每個要求,並嘗試重新擷取。如有任何要求無法重新擷取,系統會將該要求排入佇列中的相同位置 (這會註冊下一個同步事件的重試作業)。
replayRequests
函式如下所示:() => {...}
-
returns
Promise<void>
-
-
shiftRequest
void
移除並傳回佇列中的第一個要求 (以及要求的時間戳記和任何中繼資料)。傳回的物件格式為:
{request, timestamp, metadata}
。shiftRequest
函式如下所示:() => {...}
-
returns
Promise<QueueEntry>
-
-
大小
void
傳回佇列中出現的項目數量。請注意,過期項目 (每
maxRetentionTime
) 也會計入這項計數。size
函式如下所示:() => {...}
-
returns
Promise<number>
-
-
unshiftRequest
void
將傳遞的要求儲存在佇列開頭的 IndexedDB 中 (含時間戳記和任何中繼資料)。
unshiftRequest
函式如下所示:(entry: QueueEntry) => {...}
-
項目
QueueEntry
-
returns
Promise<void>
-
QueueOptions
屬性
-
forceSyncFallback
布林值 (選用)
-
maxRetentionTime
數字 選填
-
onSync
OnSyncCallback 選用
QueueStore
用於管理在 IndexedDB 中儲存佇列要求的類別,該類別會依據佇列名稱建立索引,以便輕鬆存取。
大多數開發人員不需要直接存取此類別,此類別可用於進階用途。
屬性
-
建構函式
void
建立此執行個體與佇列執行個體的關聯,以便使用其佇列名稱來識別新增的項目。
constructor
函式如下所示:(queueName: string) => {...}
-
queueName
字串
-
returns
-
-
deleteEntry
void
刪除指定 ID 的項目。
警告:這個方法並不會確保已刪除的項目屬於這個佇列 (也就是與
queueName
相符)。不過,由於這個類別不會公開公開,因此可以接受這項限制。如果另外進行檢查,這個方法會速度過慢。deleteEntry
函式如下所示:(id: number) => {...}
-
id
號碼
-
returns
Promise<void>
-
-
getAll
void
傳回儲存庫中符合
queueName
的所有項目。getAll
函式如下所示:() => {...}
-
returns
Promise<QueueStoreEntry[]>
-
-
popEntry
void
移除並傳回佇列中符合
queueName
的最後一個項目。popEntry
函式如下所示:() => {...}
-
returns
Promise<QueueStoreEntry>
-
-
pushEntry
void
附加佇列的最後一項項目。
pushEntry
函式如下所示:(entry: UnidentifiedQueueStoreEntry) => {...}
-
項目
UnidentifiedQueueStoreEntry
-
returns
Promise<void>
-
-
shiftEntry
void
移除並傳回佇列中符合
queueName
的第一個項目。shiftEntry
函式如下所示:() => {...}
-
returns
Promise<QueueStoreEntry>
-
-
大小
void
傳回商店中符合
queueName
的項目數量。size
函式如下所示:() => {...}
-
returns
Promise<number>
-
-
unshiftEntry
void
請先在佇列中前置一個項目。
unshiftEntry
函式如下所示:(entry: UnidentifiedQueueStoreEntry) => {...}
-
項目
UnidentifiedQueueStoreEntry
-
returns
Promise<void>
-
StorableRequest
可輕鬆將要求序列化和取消序列化的類別,以便儲存在 IndexedDB 中。
大多數開發人員不需要直接存取此類別,此類別可用於進階用途。
屬性
-
建構函式
void
接受要求資料物件,該物件可用來建構
Request
,但也可以儲存在索引資料庫。constructor
函式如下所示:(requestData: RequestData) => {...}
-
requestData
RequestData
要求資料物件,包含
url
加上 [requestInit]https://fetch.spec.whatwg.org/#requestinit
的任何相關屬性。
-
returns
-
-
clone
void
建立並傳回執行個體的深度本機副本。
clone
函式如下所示:() => {...}
-
returns
-
-
toObject
void
傳回例項
_requestData
物件的深度本機副本。toObject
函式如下所示:() => {...}
-
returns
RequestData
-
-
toRequest
void
將這個執行個體轉換為要求。
toRequest
函式如下所示:() => {...}
-
returns
要求
-
-
fromRequest
void
將要求物件轉換為可複製或建立 JSON 字串的純物件。
fromRequest
函式如下所示:(request: Request) => {...}
-
申請。
要求
-
returns
Promise<StorableRequest>
-