[slightlyoff/ServiceWorker] Eliminating SW startup latency for common case (#920)

Apologies in advance for the length of this issue.

A few weeks ago I was discussing the topic of the upcoming ["PlzNavigate" feature](https://bugs.chromium.org/p/chromium/issues/detail?id=368813) with @naskooskov, @n8schloss, and @bmaurer.

The TL;DR of PlzNavigate is that navigation actions in Chromium will not be handled as they currently are -- sending them through a Renderer process which then routes them to the Browser process for eventual dispatch by the network stack -- and will instead be immediately routed to the Browser-side network stack, improving time-to-navigation in the common (non-SW-controlled) case. This is beneficial in the PlzNavigate world which is much more aggressively multi-process oriented. Saving the time to create processes is a big win, particularly on Android which "features" particularly slow native process creation.

In Chromium (and one assumes similarly architected browsers), this means that PlzNavigate-style request optimisation runs afoul of Service Worker handling of these requests. This isn't particularly satisfying as the SW may indeed choose to make a request for the top-level resource from the network. Indeed, waiting to issue these requests on Service Worker startup is being reported by large sites as a regression in the 10s or even hundred+ millisecond range. This is notable on sites which do not handle fetches for top-level documents but only want to use SWs for caching.

What if we could enable PlzNavigate _and_ remove the hit generated by SW startup?

The idea in the following proposal is to allow a style of declarative navigation request decoration for these "preflight" navigation requests, allowing the Service Worker to use (or discard) the response. If no decoration is added and the site's SW decides to handle the request directly (e.g. with a `e.respondWith(fetch(e.request))`), nothing should break. Similarly, it's a goal to avoid sending the results of the "preflight" request to the document without the Service Worker's involvement.

To accomplish this, the proposal we sketched out on the whiteboard was to allow the `onfetch` event that corresponds to the navigation to have access to the original (preflight) response. To enable a savvy server-side to repurpose this preflight navigation to, e.g., send up-to-date data in a different format than HTML (imagine JSON or similar), we'd also allow the Service Worker to register a header to pass along with the preflight'd navigation request. All together, the strawman looks roughly like:

```js
self.onactivate = (e) => {
  // If unset, preflight requests are sent without special marking
  e.setPreflightHeader("X-Site-Specific-Header", "thinger");

  // ...
}

self.onfetch = (e) => {
  if (e.preflightResponse) {
    // This is a navigation fetch which has already been issued.
    // If the `preflightResponse` isn't used, then everything proceeds as
    // if it hadn't been sent in the first place.
  }
}
```

Obviously the names are bike-sheddable. The goal however isn't to be super declarative about deciding what "routes" are handled in which style. Instead, it's to allow the maximum of flexibility for cooperating servers and clients to eliminate SW startup latency.

Thoughts?

/cc @jakearchibald @wanderview @jungkees @mkruisselbrink 

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/slightlyoff/ServiceWorker/issues/920

Received on Tuesday, 28 June 2016 01:47:14 UTC