Re: [ServiceWorker] Allow respondWith() to be called asynchronously or allow some way to cancel the response. (#836)

The best I could come up with that approximates the original desired semantics - multiple cooperating handlers asynchronously decide if they are the one that will service the request, and have unfettered access to the `fetch` event - is something like the following. Like @mkruisselbrink I'm relying on the fact that multiple handlers see the same `Event` object and can decorate it.

```js
function Helper(event) {
  var promises = [], count = 0, resolve;
  this.response = new Promise(r => resolve = r);
  this.add = function(p) {
    p.then(
      r => resolve(r),
      () => {
        if (++count === promises.length)
          resolve(fetch(event.request));
      });
  };
}

// Multiple of these allowed
self.addEventListener('fetch', event => {
  if (!event.helper) event.helper = new Helper(event);
  event.helper.add(new Promise((resolve, reject) => {
    self.caches.match(event.request).then(response => {
      if (response)
        resolve(response);
      else
        reject();
    }).catch(reject);
  }));
  event.respondWith(event.helper.response);
});
```

I believe this has a race, though: if the first handler's cache check resolves before the second event handler is run, the Helper will conclude all associated Promises have completed. That could be addressed with a `setTimeout(..., 0)`, or maybe we can't run microtasks during event dispatch and it's moot.

That's an awful lot of boilerplate per handler, though. So I agree that middleware is probably cleanest. If the handlers add Request → Promise<Response> functions to a collection (`self.fetchHandlers`, say) then the actual fetch handler can "race" them all, ignoring ones that reject. If all reject, it falls back to `fetch(event.request)`


---
Reply to this email directly or view it on GitHub:
https://github.com/slightlyoff/ServiceWorker/issues/836#issuecomment-186450287

Received on Friday, 19 February 2016 23:31:11 UTC