5

我已经完成了一个简单的 service-worker 来推迟我的 JS 应用程序失败的请求(按照这个示例)并且它运行良好。但是当请求成功时我仍然有一个问题:请求完成了两次。一次正常,一次由服务人员由于fetch()我猜的电话。

这是一个真正的问题,因为当客户端想要保存数据时,它们被保存了两次......

这是代码:

const queue = new workbox.backgroundSync.Queue('deferredRequestsQueue');
const requestsToDefer = [
  { urlPattern: /\/sf\/observation$/, method: 'POST' }
]
function isRequestAllowedToBeDeferred (request) {
  for (let i = 0; i < requestsToDefer.length; i++) {
    if (request.method && request.method.toLowerCase() === requestsToDefer[i].method.toLowerCase()
      && requestsToDefer[i].urlPattern.test(request.url)) {
      return true
    }
  }
  return false
}

self.addEventListener('fetch', (event) => {
  if (isRequestAllowedToBeDeferred(event.request)) {
    const requestClone = event.request.clone()
    const promiseChain = fetch(requestClone)
      .catch((err) => {
        console.log(`Request added to queue: ${event.request.url}`)
        queue.addRequest(event.request)

        event.respondWith(new Response({ deferred: true, request: requestClone }))
      })

    event.waitUntil(promiseChain)
  }
})

如何做好?

编辑:

我想我不必重新fetch()请求(因为这是第二个请求的原因)并等待触发的初始请求的响应,fetchEvent但我不知道该怎么做。fetchEvent似乎没有办法等待(和阅读)响应。

我走对了吗?如何知道触发的请求何时fetchEvent有响应?

4

2 回答 2

2

您正在event.respondWith(...)异步调用,在promiseChain.

您需要在事件处理程序event.respondWith()的初始执行期间同步调用。fetch这是给服务工作者的“信号”,它是你的fetch处理程序,而不是另一个注册fetch的处理程序(或浏览器默认值),它将为传入请求提供响应。

(虽然您event.waitUntil(promiseChain)在初始执行期间同步调用,但实际上并没有对响应请求做任何事情——它只是确保服务工作者在promiseChain执行时不会自动终止。)

退后一步,我认为如果按照文档中的示例workbox.backgroundSync.Plugin使用with workbox.routing.registerRoute(),您可能会更幸运地完成您正在尝试做的事情:

workbox.routing.registerRoute(
  /\/sf\/observation$/,
  workbox.strategy.networkOnly({
    plugins: [new workbox.backgroundSync.Plugin('deferredRequestsQueue')]
  }),
  'POST'
);

这将告诉 Workbox 拦截任何POST与您的 RegExp 匹配的请求,尝试使用网络发出这些请求,如果失败,自动排队并通过后台同步 API 重试它们。

于 2018-05-02T17:09:07.373 回答
2

捎带 Jeff Posnick 的答案,您需要调用event.respondWith()并将调用包含fetch()在它的async function().

例如:

self.addEventListener('fetch', function(event) {
    if (isRequestAllowedToBeDeferred(event.request)) {
        event.respondWith(async function(){
            const promiseChain = fetch(event.request.clone())
                .catch(function(err) {
                    return queue.addRequest(event.request);
            });
            event.waitUntil(promiseChain);
            return promiseChain;
        }());
    }
});

这将避免您在第二次 ajax 调用时遇到的问题。

于 2018-07-24T00:30:39.313 回答