Service Workers:浏览器什么时候再次同步回来?

Service Workers: when does the browser sync back again?

我正在使用 Google Workbox 构建一个渐进式 Web 应用程序。我已经使用 bgSync(在我的构建文件夹中)设置了一个服务工作者,以便我的 POST 请求被推送到队列并在用户重新获得连接时发送到我的端点,但是同步事件到底什么时候发生?

出于开发目的,我使用 Chrome 中包含的 "Sync" 按钮,详见此答案:,但这是手动的,我希望请求是应用程序恢复在线后立即发送到端点,但是当我连接时我的请求没有发送,我必须手动单击 "Sync" 按钮才能发生,它确实工作得很好,但用户赢了在真实场景中单击“同步”按钮。

准确地说,我想知道在我的 service-worker 中是否有办法检测应用程序何时恢复在线并强制同步。或者知道同步何时发生。这是一个供参考的片段(使用 Workbox 3.0.0):

const bgSyncPlugin = new workbox.backgroundSync.Plugin('myQueue', {
  callbacks: {
    requestWillEnqueue: (storableRequest) => {}, // I show a push notification indicating user is offline
    requestWillReplay: (storableRequest) => {},
    queueDidReplay: (storableRequestArray) => {} // If I get a response, I show a push notification
      }
   },
);

workbox.routing.registerRoute(
  "https://myapi.com/action",
  workbox.strategies.networkOnly({
    plugins: [bgSyncPlugin]
  }),
  'POST'
);

因此,从今天开始,Chrome 中的后台同步尝试将排队的请求推送 3 次(工作箱或后台同步文档中从未解释过):

  • 第一次:真正第一次尝试请求时,浏览器发现用户没有连接,所以将请求放入indexedDB。
  • 第二次:第一次尝试后整整 5 分钟。
  • 第三次:第一次尝试后整整 15 分钟。

如果用户在 15 分钟后没有连接,那么请求就会卡在 indexedDB 中,直到一个新的排队请求尝试推送其余请求。这在我们期望用户数小时没有互联网连接的情况下不是很有帮助。

有计划(自 2016 年起!)实施 PeriodicSync,这将让开发人员选择浏览器尝试同步的次数和时间,但从未真正实施,请参阅:https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/periodicSync

尽管我提出了一个笨拙的解决方案,它可能不是最好的解决方案,但它满足了我的需要。有一个同步事件,我们可以操纵它来重试我们卡在 indexedDB 中的请求。我们需要使用 Workbox 队列 class 而不是插件。

// our service worker file
// we create a push notification function so the user knows when the requests are being synced

const notificate = (title, message) => {
    self.registration.showNotification(title, {
    body: message,
    icon: '/image.png',
    tag: 'service-worker'
 })
}

// let's create our queue
const queue = new workbox.backgroundSync.Queue('myQueue', {
   callbacks: {
       requestWillEnqueue: () => {
       notificate('You are offline! ', 'Your request has been submitted to the Offline 
queue. The queue will sync with the server once you are back online.')
    }
});

// sync event handler
self.addEventListener("sync", (ev) => {
  queue.replayRequests().then((a) => {
    notificate('Syncing Application... ', 'Any pending requests will be sent to the 
server.');
  }).catch(
    notificate('We could not submit your requests. ❌', 'Please hit the \'Sync Pending 
Requests\' button when you regain internet connection.')
    );
 });

现在在我们的 HTML/React/Node 视图文件中,我们可以做:

  // this will trigger our Sync event
  <button type="button" onClick={navigator.serviceWorker.ready.then(reg =>
      reg.sync.register('myEvent'))}>{'Sync Pending
  Requests'}</button>

注意我创建了一个 html 按钮强制我的 service worker 运行 queue.replayRequests(),所以后台同步功能不会自动发生,我必须手动点击按钮让它发生。

您可以通过利用以分钟为值的 maxRetentionTime 参数来更改重试的时间段。例如,如果你想重试 2 天,你可以像这样初始化队列:

const queue = new workbox.backgroundSync.Queue('requestsQueue', {
    maxRetentionTime: 48 * 60 //2 days
});

当然,如果队列中的请求执行成功,则不会再重试运行。

文档中的更多信息:https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.backgroundSync.Queue