Serviceworker: Should 'fetch' be an event, or some different API?

Created on 29 Apr 2014  路  5Comments  路  Source: w3c/ServiceWorker

Some have suggested 'fetch' shouldn't be an event, and should be another kind of callback where you return a response/promise to indicate interest in the event.

this.onfetch = function(event) {
  event.respondWidth(
    caches.match(event.request).catch(function() {
      return fetch('kittens.jpg');
    })
  );
};

// vs

fetchIntercept(function(requestDetails) {
  return caches.match(requestDetails.request).catch(function() {
    return fetch('kittens.jpg');
  });
});

Why it should be an event:

  • Like 'click', 'fetch' is a thing that happens
  • Intercepting a default action & doing something else is what deveopers use events for
  • You can have multiple listeners

Why it shouldn't be an event:

  • Currently respondWith calls preventDefault and stopImmediatePropogation, is this breaking the model?
  • ...

@Hixie @stefanpenner @annevk - any further cases against?

fetch lifecycle medium risk wontfix

All 5 comments

The SW design adds functionality to events, whereas they are designed to be a cheap notification feature for state/date.

Events are also not supposed to have side effects. (E.g. observing there are listeners.)

I think something like fetchHooks.add() / remove() / ... could work here. Not sure about the other "events" we have.

Same for oninstall and its waitUntil event method. I really feel these are strong code smells. We're using events to express a different pattern, here.

What we're looking at during installation is to carve a space in the algorithm itself for the developer to do stuff. That's a common design pattern: a template method. The dynamic characteristics of JavaScript allow us to define it in the instance object itself rather than need to subclass SW. The fact that it might need to be async just means that a call to it has to be wrapped using Promise.resolve, e.g. in pseudo js code:

if (this.setup) {
    Promise.resolve(this.setup()).then(_nextStepOfTheAlgo);
} else {
    _nextStepOfTheAlgo();
}

Which allows the developer to write:

this.setup = function() {
    var shellResources = new Cache();
    return shellResources.add(
        "/app.html",
        "/assets/v1/base.css",
        "/assets/v1/app.js",
        "/assets/v1/logo.png",
        "/assets/v1/intro_video.webm",
    ).then(function() {
        caches.set("shell-v1", shellResources);
    });
};

There's a strong similarity for respondWith and I like Anne's suggestion to use an express.js inspired add method here. I look into this more once I'm back at my desk.

What is the design goal of these hooks? I can think of a few that change the design.

  • Is it a one-time thing, handled by the application developer? If so, this.setup = is good.
  • Is it a low-level primitive, which more complicated frameworks can be built on top of? If so, then this.fetch = is good, and people can build "Express for service workers" which monopolizes the this.fetch = hook but then composes middleware which it inserts into the pipeline.
  • Is it a broadcast mechanism, to multiple parties? If so events might be good (Socket.IO-style). The semantics here would then be a race between which party calls e.waitUntil first, or alternately whose promise settles first.
  • Is it a pipeline of hooks, all of which wait for the previous one to asynchronously complete before moving on? If so an Express-style middleware system might work well. (The problem with this approach is that the setup then becomes very order-dependent, and also different middlewares will often monkey-patch things onto the request object for later middlewares to consume, which gets messy.)

It might be different in each case. I agree that events + waitUntil is not great. But then again, it is not horrible, as long as the semantics are well-defined (i.e. the way in which they race).

Returning promises is pretty nice though, when it can be arranged...

This isn't changing. Closing.

thegooddinosaur-disney-pixar-the-good-dinosaur-3oEduMcvxTNPlGuhH2

Was this page helpful?
0 / 5 - 0 ratings