NavigationPreloadManager
========================

The **`NavigationPreloadManager`** interface of the Service Worker API provides methods for managing the preloading of resources in parallel with service worker bootup.

 If supported, an object of this type is returned by `ServiceWorkerRegistration.navigationPreload`.
 The result of a preload fetch request is waited on using the promise returned by `FetchEvent.preloadResponse`.

Instance methods
----------------

`NavigationPreloadManager.enable()`

Enables navigation preloading, returning a `Promise` that resolves with `undefined`.

`NavigationPreloadManager.disable()`

Disables navigation preloading, returning a `Promise` that resolves with `undefined`.

`NavigationPreloadManager.setHeaderValue()`

Sets the value of the `Service-Worker-Navigation-Preload` HTTP header sent in preloading requests and returns an empty `Promise`.

`NavigationPreloadManager.getState()`

Returns a `Promise` that resolves to an object with properties that indicate whether preloading is enabled, and what value will be sent in the `Service-Worker-Navigation-Preload` HTTP header in preloading requests.

Description
-----------

 Service workers handle `fetch()` events on behalf of a site, for pages within a given scope.
 When a user navigates to a page that uses a service worker, the browser boots up the worker (if it isn't already running), then sends it a fetch event and waits for the result.
 On receiving an event, the worker returns the resource from a cache if it is present, or otherwise fetches the resource from the remote server (storing a copy for returning in future requests).

 A service worker cannot process events from the browser until it has booted.
 This is unavoidable, but usually doesn't have much impact.
 Service workers are often already started (they remain active for some time after processing other requests).
 Even if a service worker does have to boot, much of the time it may be returning values from a cache, which is very fast.
 However, in those cases where a worker has to boot before it can start fetching a remote resource, then the delay can be significant.

 The `NavigationPreloadManager` provides a mechanism to allow fetching of the resources to run in parallel with service worker boot, so that by the time the worker is able to handle the fetch request from the browser, the resource may already have been fully or partially downloaded.
 This makes the case where the worker has to start up "no worse" than when the worker is already started, and in some cases better.

 The preload manager sends the `Service-Worker-Navigation-Preload` HTTP header with preload requests, allowing responses to be customized for preload requests.
 This might be used, for example, to reduce the data sent to just part of the original page, or to customize the response based on the user's log-in state.

Examples
--------

The examples here are from Speed up Service Worker with Navigation Preloads (developer.chrome.com).

### Feature detection and enabling navigation preloading

Below we enable navigation preloading in the service worker's `activate` event handler, after first using `ServiceWorkerRegistration.navigationPreload` to determine if the feature is supported (this returns either the `NavigationPreloadManager` for the service worker or `undefined` if the feature is not supported).


```js
addEventListener("activate", (event) => {
  event.waitUntil(
    (async () => {
      if (self.registration.navigationPreload) {
        // Enable navigation preloads!
        await self.registration.navigationPreload.enable();
      }
    })(),
  );
});
```

### Using a preloaded response

The following code shows a service worker fetch event handler that uses a preloaded response (`FetchEvent.preloadResponse`).

 The `fetch` event handler calls `FetchEvent.respondWith()` to pass a promise back to the controlled page.
 This promise will resolve with the requested resource, which may be from the cache, a preloaded fetch request, or a new network request.

 If there is a matching URL request in the `Cache` object, then the code returns a resolved promise for fetching the response from the cache.
 If no match is found in the cache, the code returns the resolved preloaded response (`FetchEvent.preloadResponse`).
 If there is no matching cache entry or preloaded response, the code starts a new fetch operation from the network and returns the (unresolved) promise for that fetch operation.


```js
addEventListener("fetch", (event) => {
  event.respondWith(
    (async () => {
      // Respond from the cache if we can
      const cachedResponse = await caches.match(event.request);
      if (cachedResponse) return cachedResponse;

      // Else, use the preloaded response, if it's there
      const response = await event.preloadResponse;
      if (response) return response;

      // Else try the network.
      return fetch(event.request);
    })(),
  );
});
```

### Custom responses

 The browser sends the HTTP header `Service-Worker-Navigation-Preload` with preload requests, with a default directive value of `true`.
 This allows servers to differentiate between normal and preload fetch requests, and to send different responses in each case if required.

**Note:** If the response from preload and normal fetch operations can be different, then the server must set `Vary: Service-Worker-Navigation-Preload` to ensure that the different responses are cached.

 The header value can be changed to any other string value using `NavigationPreloadManager.setHeaderValue()` in order to provide additional context for the prefetch operation.
 For example, you might set the value to the ID of your most recently cached resource, so that the server won't return any resources unless they are actually needed.
 Similarly, you could configure the returned information based on authentication status instead of using cookies.

The code below shows how to set the value of the header directive to some variable `newValue`.


```js
navigator.serviceWorker.ready
  .then((registration) =>
    registration.navigationPreload.setHeaderValue(newValue),
  )
  .then(() => {
    console.log("Done!");
  });
```


Speed up Service Worker with Navigation Preloads > Custom responses for preloads provides a more complete example of a site where the response for an article web page is constructed from a cached header and footer, so that only the article content is returned for a prefetch.

### Getting the state

 You can use `NavigationPreloadManager.getState()` to check whether navigation preloading is enabled and to determine what directive value is sent with the
 `Service-Worker-Navigation-Preload` HTTP header for preload requests.

The code below shows how to get the promise that resolves to a `state` object and log the result.


```js
navigator.serviceWorker.ready
  .then((registration) => registration.navigationPreload.getState())
  .then((state) => {
    console.log(state.enabled); // boolean
    console.log(state.headerValue); // string
  });
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # navigation-preload-manager |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Speed up Service Worker with Navigation Preloads (developer.chrome.com)