当您向网络服务器发送数据时,有时请求会失败。它 这可能是因为用户连接已断开, 服务器关闭无论是哪种情况 。
新的 BackgroundSync API
是解决此问题的理想解决方案。当 Service Worker 检测到
网络请求失败,可以注册以接收 sync
事件,
当浏览器认为已经恢复连接时传递。
请注意,即使用户离开了网站,同步事件也会被传递
应用进行微调,这比传统的
重试失败的请求。
Workbox 后台同步功能旨在让您更轻松地使用 BackgroundSync API 的用法,并将其用法与其他 Workbox 模块集成。它 还为尚未实现 BackgroundSync。
支持 BackgroundSync API 的浏览器会自动重放失败 代表您向 由浏览器管理的时间间隔 可能在两次重放尝试之间使用指数退避算法。在 未对 BackgroundSync API 提供原生支持,Workbox Background Sync 将 会在 Service Worker 启动时自动尝试重新播放。
基本用法
使用后台同步的最简单方法是使用 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 后台同步还提供了 Queue
类,让您可以
实例化并向其中添加失败的请求系统会存储失败的请求
在 IndexedDB 中
当浏览器认为连接已恢复(即
接收同步事件时触发)。
创建队列
要创建 Workbox 后台同步队列,您需要使用 队列名称(该名称对于 origin):
import {Queue} from 'workbox-background-sync';
const queue = new Queue('myQueueName');
队列名称用作获取
register()
-ed
由全球
SyncManager
。时间是
也用作
对象存储名称
IndexedDB 数据库。
向队列添加请求
创建 Queue 实例后,您可以向其添加失败的请求。
您通过调用 .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());
});
请求加入队列后,
Service Worker 收到 sync
事件(在浏览器
认为连接已恢复)。不支持
每当 Service Worker 被触发时,BackgroundSync API 都会重试队列
启动了这要求控制 Service Worker 的页面
所以效果可能不太理想
测试 Workbox 后台同步
遗憾的是,测试 BackgroundSync 有点不直观且困难 可能的原因有很多种
测试实现效果的最佳方法是执行以下操作:
- 加载页面并注册 Service Worker。
- 关闭计算机的网络或网络服务器。
- 请勿离线使用 Chrome 开发者工具。“离线访问”复选框 开发者工具只会影响来自页面的请求。Service Worker 请求 将会继续进行下去
- 使用 Workbox 后台同步功能发出应加入队列的网络请求。
- 您可在以下位置查看请求是否已排入队列:
Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
- 您可在以下位置查看请求是否已排入队列:
- 现在,打开网络或网络服务器。
通过以下方式强制提前
sync
事件:Chrome DevTools > Application > Service Workers
,输入workbox-background-sync:<your queue name>
,其中<your queue name>
应为 设置队列的名称,然后点击“同步”按钮。您应该会看到失败的请求通过网络请求 IndexedDB 数据现在应该为空,因为请求已被 已成功重放。
类型
BackgroundSyncPlugin
实现 fetchDidFail
生命周期回调的类。这样,
更轻松地将失败的请求添加到后台同步队列中。
属性
-
构造函数
void
constructor
函数如下所示:(name: string, options?: QueueOptions) => {...}
-
name
字符串
请参阅
workbox-background-sync.Queue
有关参数详情的文档。 -
选项
QueueOptions 可选
-
Queue
用于管理在 IndexedDB 中存储失败请求以及重试这些请求的类 。存储和重放过程的所有部分均可通过 回调。
属性
-
构造函数
void
使用指定选项创建 Queue 实例
constructor
函数如下所示:(name: string, options?: QueueOptions) => {...}
-
name
字符串
此队列的唯一名称。此名称必须是 唯一,因为它用于注册同步事件和存储请求, IndexedDB 中特定于此实例的 IndexedDB。如果遇到以下情况,系统将抛出错误 检测到重复名称。
-
选项
QueueOptions 可选
-
返回
-
-
name
字符串
-
getAll
void
返回所有未过期的条目(每
maxRetentionTime
)。 所有过期的条目都会从队列中移除。getAll
函数如下所示:() => {...}
-
返回
Promise<QueueEntry[]>
-
-
popRequest
void
删除并返回队列中的最后一个请求(及其 时间戳和任何元数据)。返回的对象采用以下形式:
{request, timestamp, metadata}
。popRequest
函数如下所示:() => {...}
-
返回
Promise<QueueEntry>
-
-
pushRequest
void
将传递的请求存储在 IndexedDB 中(包含其时间戳和 元数据)。
pushRequest
函数如下所示:(entry: QueueEntry) => {...}
-
入口
QueueEntry
-
返回
承诺<void>
-
-
registerSync
void
使用此实例独有的标记注册同步事件。
registerSync
函数如下所示:() => {...}
-
返回
承诺<void>
-
-
replayRequests
void
循环遍历队列中的每个请求,并尝试重新获取。 如果任何请求未能重新提取,就会被放回 队列(为下一个同步事件注册重试)。
replayRequests
函数如下所示:() => {...}
-
返回
承诺<void>
-
-
shiftRequest
void
删除并返回队列中的第一个请求(及其 时间戳和任何元数据)。返回的对象采用以下形式:
{request, timestamp, metadata}
。shiftRequest
函数如下所示:() => {...}
-
返回
Promise<QueueEntry>
-
-
大小
void
返回队列中显示的条目数。 请注意,过期条目(每个
maxRetentionTime
)也会计入此计数。size
函数如下所示:() => {...}
-
返回
Promise<number>
-
-
unshiftRequest
void
将传递的请求存储在 IndexedDB 中(包含其时间戳和 元数据)添加到队列的开头。
unshiftRequest
函数如下所示:(entry: QueueEntry) => {...}
-
入口
QueueEntry
-
返回
承诺<void>
-
QueueOptions
属性
-
forceSyncFallback
布尔值(可选)
-
maxRetentionTime
编号(选填)
-
onSync
OnSyncCallback(可选)
QueueStore
一个类,用于管理 IndexedDB 中队列的存储请求, 按队列名称编入索引,更便于访问。
大多数开发者不需要直接访问此类; 它公开用于高级用例。
属性
-
构造函数
void
将此实例与 Queue 实例相关联,以便可以 由其队列名称标识
constructor
函数如下所示:(queueName: string) => {...}
-
queueName
字符串
-
-
deleteEntry
void
删除指定 ID 的条目。
警告:此方法不能确保已删除的条目属于 队列(即与
queueName
匹配)。但这种限制是可以接受的 因为此类不公开提供。如果再进行一次检查 此方法会比实际速度慢。deleteEntry
函数如下所示:(id: number) => {...}
-
id
number
-
返回
承诺<void>
-
-
getAll
void
返回存储区中与
queueName
匹配的所有条目。getAll
函数如下所示:() => {...}
-
返回
Promise<QueueStoreEntry[]>
-
-
popEntry
void
移除并返回队列中与
queueName
匹配的最后一个条目。popEntry
函数如下所示:() => {...}
-
返回
Promise<QueueStoreEntry>
-
-
pushEntry
void
在队列中最后附加一个条目。
pushEntry
函数如下所示:(entry: UnidentifiedQueueStoreEntry) => {...}
-
入口
UnidentifiedQueueStoreEntry
-
返回
承诺<void>
-
-
shiftEntry
void
移除并返回队列中与
queueName
匹配的第一个条目。shiftEntry
函数如下所示:() => {...}
-
返回
Promise<QueueStoreEntry>
-
-
大小
void
返回存储区中与
queueName
匹配的条目数。size
函数如下所示:() => {...}
-
返回
Promise<number>
-
-
unshiftEntry
void
首先在队列中添加条目。
unshiftEntry
函数如下所示:(entry: UnidentifiedQueueStoreEntry) => {...}
-
入口
UnidentifiedQueueStoreEntry
-
返回
承诺<void>
-
StorableRequest
一个类,用于更轻松地对请求进行序列化和反序列化, 可以存储在 IndexedDB 中。
大多数开发者不需要直接访问此类; 它公开用于高级用例。
属性
-
构造函数
void
它接受可用于构造
Request
,但也可以存储在 IndexedDB 中。constructor
函数如下所示:(requestData: RequestData) => {...}
-
requestData
RequestData
包含
url
以及 [requestInit]https://fetch.spec.whatwg.org/#requestinit
。
-
-
clone
void
创建并返回实例的深度克隆。
clone
函数如下所示:() => {...}
-
toObject
void
返回实例
_requestData
对象的深度克隆。toObject
函数如下所示:() => {...}
-
返回
RequestData
-
-
toRequest
void
将此实例转换为请求。
toRequest
函数如下所示:() => {...}
-
返回
请求
-
-
fromRequest
void
将 Request 对象转换为可进行结构化的普通对象。 克隆或经过 JSON 字符串化处理。
fromRequest
函数如下所示:(request: Request) => {...}
-
request
请求
-
返回
Promise<StorableRequest>
-