通过服务工作者的请求完成两次

时间:2018-05-02 07:34:18

标签: javascript fetch service-worker workbox

我已经完成了一个简单的服务工作者来推迟我的JS应用程序失败的请求(在this example之后)并且它运行良好。 但是当请求成功时我仍然遇到问题:请求完成两次。由于我猜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的请求何时有响应?

2 个答案:

答案 0 :(得分:1)

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

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

(当你在初始执行期间同步调用event.waitUntil(promiseChain)时,实际上并没有做任何关于响应请求的事情 - 它只是确保服务工作者不会自动被杀死{{ 1}}正在执行。)

退一步,我认为如果你在example from the docs之后使用promiseChainworkbox.backgroundSync.Plugin,你可能会更好地完成你要做的事情:

workbox.routing.registerRoute()

这将告诉Workbox拦截与您的RegExp匹配的任何workbox.routing.registerRoute( /\/sf\/observation$/, workbox.strategy.networkOnly({ plugins: [new workbox.backgroundSync.Plugin('deferredRequestsQueue')] }), 'POST' ); 请求,尝试使用网络发出这些请求,如果失败,则自动排队并通过后台同步API重试它们。

答案 1 :(得分:0)

Pi带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调用时遇到问题。

相关问题