Workbox-background-sync

当您向网络服务器发送数据时,有时请求会失败。它 这可能是因为用户连接已断开, 服务器关闭无论是哪种情况 。

新的 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,很可能是因为 网络故障也就是说,如果存在 收到的回复中包含 4xx5xx 错误状态。 如果您想重试导致出现 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 有点不直观且困难 可能的原因有很多种

测试实现效果的最佳方法是执行以下操作:

  1. 加载页面并注册 Service Worker。
  2. 关闭计算机的网络或网络服务器。
    • 请勿离线使用 Chrome 开发者工具。“离线访问”复选框 开发者工具只会影响来自页面的请求。Service Worker 请求 将会继续进行下去
  3. 使用 Workbox 后台同步功能发出应加入队列的网络请求。
    • 您可在以下位置查看请求是否已排入队列: Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. 现在,打开网络或网络服务器。
  5. 通过以下方式强制提前 sync 事件: Chrome DevTools > Application > Service Workers,输入 workbox-background-sync:<your queue name>,其中 <your queue name> 应为 设置队列的名称,然后点击“同步”按钮。

    Chrome 开发者工具中的“同步”按钮示例

  6. 您应该会看到失败的请求通过网络请求 IndexedDB 数据现在应该为空,因为请求已被 已成功重放。

类型

BackgroundSyncPlugin

实现 fetchDidFail 生命周期回调的类。这样, 更轻松地将失败的请求添加到后台同步队列中。

属性

Queue

用于管理在 IndexedDB 中存储失败请求以及重试这些请求的类 。存储和重放过程的所有部分均可通过 回调。

属性

  • 构造函数

    void

    使用指定选项创建 Queue 实例

    constructor 函数如下所示:

    (name: string, options?: QueueOptions) => {...}

    • name

      字符串

      此队列的唯一名称。此名称必须是 唯一,因为它用于注册同步事件和存储请求, IndexedDB 中特定于此实例的 IndexedDB。如果遇到以下情况,系统将抛出错误 检测到重复名称。

    • 选项

      QueueOptions 可选

  • name

    字符串

  • getAll

    void

    返回所有未过期的条目(每 maxRetentionTime)。 所有过期的条目都会从队列中移除。

    getAll 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;QueueEntry[]&gt;

  • popRequest

    void

    删除并返回队列中的最后一个请求(及其 时间戳和任何元数据)。返回的对象采用以下形式: {request, timestamp, metadata}

    popRequest 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;QueueEntry&gt;

  • pushRequest

    void

    将传递的请求存储在 IndexedDB 中(包含其时间戳和 元数据)。

    pushRequest 函数如下所示:

    (entry: QueueEntry) => {...}

    • 入口

      QueueEntry

    • 返回

      承诺<void>

  • registerSync

    void

    使用此实例独有的标记注册同步事件。

    registerSync 函数如下所示:

    () => {...}

    • 返回

      承诺<void>

  • replayRequests

    void

    循环遍历队列中的每个请求,并尝试重新获取。 如果任何请求未能重新提取,就会被放回 队列(为下一个同步事件注册重试)。

    replayRequests 函数如下所示:

    () => {...}

    • 返回

      承诺<void>

  • shiftRequest

    void

    删除并返回队列中的第一个请求(及其 时间戳和任何元数据)。返回的对象采用以下形式: {request, timestamp, metadata}

    shiftRequest 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;QueueEntry&gt;

  • 大小

    void

    返回队列中显示的条目数。 请注意,过期条目(每个 maxRetentionTime)也会计入此计数。

    size 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;number&gt;

  • 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&lt;QueueStoreEntry[]&gt;

  • popEntry

    void

    移除并返回队列中与 queueName 匹配的最后一个条目。

    popEntry 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;QueueStoreEntry&gt;

  • pushEntry

    void

    在队列中最后附加一个条目。

    pushEntry 函数如下所示:

    (entry: UnidentifiedQueueStoreEntry) => {...}

    • 入口

      UnidentifiedQueueStoreEntry

    • 返回

      承诺<void>

  • shiftEntry

    void

    移除并返回队列中与 queueName 匹配的第一个条目。

    shiftEntry 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;QueueStoreEntry&gt;

  • 大小

    void

    返回存储区中与 queueName 匹配的条目数。

    size 函数如下所示:

    () => {...}

    • 返回

      Promise&lt;number&gt;

  • 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

      请求