4

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

出于开发目的,我使用 Chrome 中包含的“同步”按钮,如以下答案所述:如何手动触发后台同步(用于测试)?,但这是手动的,我希望应用程序重新联机后立即将请求发送到端点,但是当我获得连接时,我的请求没有发送,我必须手动单击“同步”按钮会发生,并且它确实工作得很好,但用户不会在真实场景中单击“同步”按钮。

准确地说,我想知道在我的服务工作者内部是否有办法检测应用程序何时重新上线,并强制同步。或者知道同步发生的时间。这是一个供参考的片段(使用 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'
);
4

2 回答 2

4

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

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

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

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

我想出了一个笨拙的解决方案,可能不是最好的,但它可以满足我的需要。有一个同步事件,我们可以操纵它来重试我们停留在 indexedDB 中的请求。我们需要使用 Workbox Queue 类而不是 Plugin。

// 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(),因此后台同步功能不会自动发生,我必须手动单击一个按钮才能发生。

于 2019-01-22T19:47:36.713 回答
0

您可以通过利用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

于 2019-05-23T17:28:34.647 回答