Intent to Implement: Navigation preload for service workers

288 views
Skip to first unread message

Matt Falkenhagen

unread,
Nov 1, 2016, 3:06:33 AM11/1/16
to blink-dev

Contact emails

fal...@chromium.org, ho...@chromium.org, kenji...@chromium.org


Spec

This feature will be part of the Service Workers spec. It is under discussion here, and the spec changes are in a WIP patch here.


Summary

Navigation preload is an extension of the Service Worker API which will let the browser send a “preload” network request for a navigation without blocking on the fetch event handler of the relevant service worker. The service worker will then have access to the preload response inside its fetch event handler. Common use cases are to respond with the preload response directly, or use it to populate the response.


Authors opt in to this behavior by calling ServiceWorkerRegistration.navigationPreload.enable().


In the default case, where navigation preload is not enabled, the browser first dispatches the fetch event to the service worker, which might involve starting the worker. The browser then only starts fetching the URL if the worker falls back to network, by not calling event.respondWith(), or manually requests it by doing something like event.respondWith(fetch(request)).


Motivation

This API allows web authors to optimize navigations by starting the network request for the main resource while the service worker is started and getting ready to execute its fetch event handler.


For a site that has a fetch event handler but does not cache the main resource, the service worker can now call respondWith(preloadResponse) for the navigation request, which should result in faster navigation than respondWith(fetch(request)) or falling back to network.


Sites can also use the preloadResponse to inject fresh data from the server into a response that also includes cached content. For example, the fetch event handler may:

  • Respond with a stream

  • Pipe “page shell” HTML from CacheStorage to the stream

  • Pipe data from the preloadResponse to the stream


Interoperability and Compatibility Risk

The spec is still developing and our implementation will track the spec. Mozilla, Apple, and Microsoft are active in spec discussion and are generally positive about this addition; see in particular notes from the F2F on July 30 here.


Ongoing technical constraints

None.


Will this feature be supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?

Yes.


OWP launch tracking bug

https://bugs.chromium.org/p/chromium/issues/detail?id=661071


Link to entry on the feature dashboard

https://www.chromestatus.com/feature/5734842339688448


Requesting approval to ship?

No.

Alex Russell

unread,
Nov 1, 2016, 3:56:16 AM11/1/16
to Matt Falkenhagen, blink-dev
Could not be more excited about this! This will have huge positive impacts on some of the largest SW-using sites on the web.

Regards
--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Ilya Grigorik

unread,
Nov 1, 2016, 2:04:40 PM11/1/16
to Matt Falkenhagen, blink-dev
I'm reading through the spec patch.. but still having a hard time piecing everything together: how do I, as a developer, actually use this? Do we have an example page that demonstrates how I trigger these preloads, and then respond with them, etc? What's the point of enable/disable?

Matt Falkenhagen

unread,
Nov 1, 2016, 9:37:09 PM11/1/16
to Ilya Grigorik, blink-dev
Yes, we need an example page. The current design is:
- enable()/disable() toggles whether navigation preload is enabled
- when enabled, all navigations inside the service worker's scope trigger a navigation preload
- the FetchEvent API has a preloadResponse object
- Navigation preload requests contain a 'Service-Worker-Navigation-Preload' header. Its value defaults to 'true' and can be customized by the author.

Prototype code (untested, subject to API changes):

addEventListener('activate', e => {
  // Once enable() settles, all navigations inside this worker's scope trigger a navigation preload.
  e.waitUntil(registration.navigationPreload.enable());
});

// Simple use case: respond with preloadResponse
addEventListener('fetch', e => {
  if (e.request.mode == 'navigate') {
    e.respondWith(e.preloadResponse.then(response => { return response || fetch(e.request); });
  }
});

// More complex use case: pipe preloadResponse to a stream
self.addEventListener('fetch', evt => {
  if (e.request.mode != 'navigate')
    return;
  var controller;
  var stream = new ReadableStream({ start: c => controller = c });
  var encoder = new TextEncoder();
  evt.respondWith(new Response(stream));
  evt.waitUntil(caches.open('my-cache')
    .then(cache => cache.match('cached-page'))
    .then(resp => resp.text())
    .then(data => {
      controller.enqueue(encoder.encode(data));
      return evt.preloadResponse;
     })
     .then(resp => resp.text())
     .then(data => {
       controller.enqueue(encoder.encode(data));
       controller.close();
    }));
});

Joe Medley

unread,
Nov 9, 2016, 1:05:23 PM11/9/16
to blink-dev
Will this be behind a flag or on by default in 57?

On Tuesday, November 1, 2016 at 12:06:33 AM UTC-7, Matt Falkenhagen wrote:

Contact emails

Rick Byers

unread,
Nov 9, 2016, 3:34:04 PM11/9/16
to Joe Medley, blink-dev
On Wed, Nov 9, 2016 at 10:05 AM, 'Joe Medley' via blink-dev <blin...@chromium.org> wrote:
Will this be behind a flag or on by default in 57?

This is just an "intent to implement" so it's too early to say when (or even whether) it will ship.

Matt Falkenhagen

unread,
Nov 9, 2016, 7:43:43 PM11/9/16
to Rick Byers, Joe Medley, blink-dev
Right. I'm guessing you saw the M-57 on the OWP launch bug. The bug template asked to fill in a milestone, so I gave my best guess only.
Reply all
Reply to author
Forward
0 new messages