diff --git a/README.md b/README.md index 7c2ca5b9..479e87f7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ To understand the design and how you might build apps with ServiceWorkers, see t ## Spec and API Development -For the nitty-gritty of the API, the [draft W3C specification](//slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html) and [`service_worker.ts`](//github.com/slightlyoff/ServiceWorker/blob/master/service_worker.ts) are authoritative. +For the nitty-gritty of the API, the [draft W3C specification](//slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html) is authoritative. For implementers and developers who seek a more stable version, [Service Workers 1](//slightlyoff.github.io/ServiceWorker/spec/service_worker_1/index.html) is a right document with which the contributors only focus on fixing bugs and resolving compatibility issues. Spec development happens via [issues in this repository](https://github.com/slightlyoff/ServiceWorker/issues). For general discussion, please use the [public-webapps@w3.org mailing list](http://lists.w3.org/Archives/Public/public-webapps/) with a `Subject:` prefix of `[service-workers]`. @@ -22,16 +22,7 @@ To edit the spec locally, you'll need a copy of [the Web Components-based framew git submodule update --init --recursive ``` -To make edits to the design, please send pull requests against the TypeScript file (`service_worker.ts`) and spec (`spec/service_worker/index.html`). Changes to the spec without corresponding changes to the `.ts` file will not be accepted. - -Building the JS version of the TypeScript API description isn't essential, but here's how: - -```sh -# From the root of the project directory -npm install -# From the root of the project directory -make -``` +To make edits to the design, please send pull requests against the spec (`spec/service_worker/index.html`). ## Examples @@ -63,7 +54,7 @@ This is to explain how we use labels and milestones to triage the issues. Note: **decided**: to record that a decision has been made. -**invalid**: when something doesn't not constitute a valid issue. +**invalid**: when something doesn't constitute a valid issue. **wontfix**: a decision has been made not to pursue this issue further. diff --git a/explainer.md b/explainer.md index 1d9d0977..022e0428 100644 --- a/explainer.md +++ b/explainer.md @@ -2,23 +2,31 @@ ## What's All This Then? +Service Workers are being developed to answer frequent questions and concerns about the web platform, including: + + * An inability to explain (in the [Extensible Web Manifesto](https://extensiblewebmanifesto.org/) sense) HTTP caching and high-level HTTP interactions like the HTML5 AppCache + * Difficulty in building offline-first web applications in a natural way + * The lack of a background execution context which many proposed capabilities could make use of + +We also note that the long lineage of declarative-only solutions ([Google Gears, [Dojo Offline](http://www.sitepen.com/blog/category/dojo-offline/), and [HTML5 AppCache](http://alistapart.com/article/application-cache-is-a-douchebag)) have failed to deliver on their promise. Each successive declarative-only approach failed in many of the same ways, so the Service Worker effort has taken a different design approach: a largely-imperative system that puts developers firmly in control. + The ServiceWorker is like a [SharedWorker](https://html.spec.whatwg.org/multipage/workers.html#sharedworker) in that it: -* runs in its own thread -* isn't tied to a particular page -* has no DOM access +* Runs in its own global script context (usually in its own thread) +* Isn't tied to a particular page +* Has no DOM access Unlike a SharedWorker, it: -* can run without any page at all -* can terminate when it isn't in use, and run again when needed -* has a defined upgrade model -* is HTTPS only (more on that in a bit) +* Can run without any page at all +* Can terminate when it isn't in use, and run again when needed (e.g., it's event-driven) +* Has a defined upgrade model +* Is HTTPS only (more on that in a bit) We can use ServiceWorker: -* to make sites work [faster and/or offline](https://www.youtube.com/watch?v=px-J9Ghvcx4) using network intercepting -* as a basis for other 'background' features such as push messaging and background sync +* To make sites work [faster and/or offline](https://www.youtube.com/watch?v=px-J9Ghvcx4) using network intercepting +* As a basis for other 'background' features such as [push messaging](http://updates.html5rocks.com/2015/03/push-notificatons-on-the-open-web) and [background synchronization](https://github.com/slightlyoff/BackgroundSync/blob/master/explainer.md) ## Getting Started @@ -84,7 +92,7 @@ If you refresh the document, it'll be under the ServiceWorker's control. You can If you shift+reload a document it'll always load without a controller, which is handy for testing quick CSS & JS changes. -Documents tend to live their whole life with a particular ServiceWorker, or none at all. However, a ServiceWorker can call `event.replace()` during the `install` event to do an immediate takeover of all pages within scope. +Documents tend to live their whole life with a particular ServiceWorker, or none at all. However, a ServiceWorker can call `self.skipWaiting()` ([spec](https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-global-scope-skipwaiting)) to do an immediate takeover of all pages within scope. ## Network intercepting @@ -99,10 +107,10 @@ You get fetch events for: * Navigations within your ServiceWorker's scope * Any requests triggered by those pages, even if they're to another origin -The means you get to hear about requests for the page itself, the CSS, JS, images, XHR, beacons… all of it. The exceptions are: +This means you get to hear about requests for the page itself, the CSS, JS, images, XHR, beacons… all of it. The exceptions are: * iframes & ``s - these will pick their own controller based on their resource URL -* ServiceWorkers - requests to fetch/update a ServiceWorker don't go through the SerivceWorker +* ServiceWorkers - requests to fetch/update a ServiceWorker don't go through the ServiceWorker * Requests triggered within a ServiceWorker - you'd get a loop otherwise The `request` object gives you information about the request such as its URL, method & headers. But the really fun bit, is you can hijack it and respond differently: @@ -113,7 +121,7 @@ self.addEventListener('fetch', function(event) { }); ``` -[Here's a live demo](https://jakearchibald.github.io/isserviceworkerready/demos/manual-response/) (you'll need to enable [some flags](http://jakearchibald.com/2014/using-serviceworker-today/#in-canary-today) to get it working in Chrome today). +[Here's a live demo](https://jakearchibald.github.io/isserviceworkerready/demos/manual-response/). `.respondWith` takes a `Response` object or a promise that resolves to one. We're creating a manual response above. The `Response` object comes from the [Fetch Spec](https://fetch.spec.whatwg.org/#response-class). Also in the spec is the `fetch()` method, which returns a promise for a response, meaning you can get your response from elsewhere: diff --git a/foreign_fetch_explainer.md b/foreign_fetch_explainer.md new file mode 100644 index 00000000..94b4ea23 --- /dev/null +++ b/foreign_fetch_explainer.md @@ -0,0 +1,49 @@ +# Foreign Fetch Explained + +## What's this about? + +Without foreign fetch Service Workers can only intercept fetches for resources when the fetch originates on a page that is controlled by the service worker. If resources from cross origin services are used, a service worker can opaquely cache these resources for offline functionality, but full offline functionality (in particular things where multiple offline apps share some common third party service, and changes in one should be visible in the other) is not possible. +With foreign fetch a service worker can opt in to intercepting requests from anywhere to resources within its scope. + +## The API + +To start intercepting requests, you'll need to register for the scopes you want to intercept in your service worker, as well as the origins from which you want to intercept requests: + +```js +self.addEventListener('install', function(e) { + e.registerForeignFetch({scopes: ['/myscope/shared_resources'], origins: ['https://www.example.com/']}); +}); +``` + +The main restriction here is that the foreign fetch scopes have to be within the scope of the service worker. + +Instead of specifying an explicit list of origins from which to intercept requests you can also use `["*"]` to indicate you want to intercept requests from all origins. + +After registering your foreign fetch scopes, and after the service worker finished installation and activation, your service worker will not only receive fetch events for pages it controls (via the `onfetch` event), but also for requests made to URLs that match your foreign fetch scopes from pages you don't control, via the new `onforeignfetch` event. + +Handling these fetch events is pretty similar to how you'd handle regular fetch events, but there are a few differences. To pass a response to the `respondWith` method in the `ForeignFetchEvent` interface, you need to wrap the response in a dictionary. This is needed because sometimes you'll need to pass extra data to `respondWith` (more on that below): + +```js +self.addEventListener('foreignfetch', function(e) { + // Do whatever local work is necesary to handle the fetch, + // or just pass it through to the network: + e.respondWith(fetch(e.request).then(response => ({response: response})); +}); +``` + +Of course just respondinging with a fetch for the same request just adds extra unneeded overhead. Generally you only want to register for foreign fetch events if the service worker can actually do something smart with the request. For example implement smarter caching than just the network cache and other regular service workers can offer. Or even more than just smarter caching, having full featured offline capable APIs. + +## What about CORS? + +Ideally having a dummy `onforeignfetch` handler like above which just passes the received request through `fetch` and responds with that would be effectively a noop. That however isn't the case. The foreign fetch service worker runs with all the credentials and ambient authority it posesses. This means that the code in the foreign fetch handler has to be extra careful to make sure it only exposes data/resources cross origin when it really meant to do that. + +To help with making it easier to write secure service workers, by default all responses passed to `respondWith` in a foreign fetch handler will be treated as opaque responses when handed back to whoever was requesting the resource. This will result in errors for the requesting party if it tried to do a CORS request. To enable a foreign fetch service worker to expose resources in a CORS like manner anyway, you can explicitly expose the request data and some subset of its headers by passing the origin making the request to respondWith: + +```js +self.addEventListener('foreignfetch', function(e) { + e.respondWith(fetch(e.request).then(response => + ({response: response, origin: e.request.origin, headers: ['...']}))); +}); +``` + +If no explicit headers are specified no headers will be exposed. diff --git a/package.json b/package.json deleted file mode 100644 index d9552f36..00000000 --- a/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "ServiceWorker", - "version": "0.0.0", - "description": "Spec for controlling and caching requests in the browser", - "repository": { - "type": "git", - "url": "git://github.com/slightlyoff/ServiceWorker.git" - }, - "license": "Apache 2.0", - "readmeFilename": "README.md", - "devDependencies": { - "typescript": "~1.0" - } -} diff --git a/publish/service_worker/WD-service-workers-20150205/index.html b/publish/service_worker/WD-service-workers-20150205/index.html new file mode 100644 index 00000000..6a3d9041 --- /dev/null +++ b/publish/service_worker/WD-service-workers-20150205/index.html @@ -0,0 +1,3546 @@ + + + Service Workers + + + + + + + + + + + +
+ + + + +

Service Workers

+

W3C Working Draft 5 February 2015

+
+
This version
+
http://www.w3.org/TR/2015/WD-service-workers-20150205/
+
Latest published version
+
http://www.w3.org/TR/service-workers/
+
Latest editor's draft
+
https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
+
Previous version
+
http://www.w3.org/TR/2014/WD-service-workers-20141118/
+
Revision history
+
https://github.com/slightlyoff/ServiceWorker/commits/master
+
Participate
+
Discuss on public-webapps@w3.org (Web Applications Working Group)
+
File bugs
+
Editors
+
Alex Russell, Google, <>
+
Jungkee Song, Samsung Electronics, <>
+
Jake Archibald, Google, <>
+
+ + + +
+
+ +

Abstract

+ +

This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.

+ +

The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.

+ +

The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.

+ +

Status of This Document

+ +

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

+ +

This document was published by the Web Applications Working Group as a Working Draft. If you wish to make comments regarding this document, please send them to public-webapps@w3.org (subscribe, archives). All feedback is welcome.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

+ +

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

+ +

This document is governed by the 1 August 2014 W3C Process Document.

+ + + +
1

Introduction

+ + +
1.1

About this Document

+ + +

All diagrams, examples, notes, are non-normative, as well as sections explicitly marked as non-normative. Everything else in this specification is normative.

+ +

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification.

+ +

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementers, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

+
+ +
1.2

Dependencies

+ + +

This document relies on the following specifications:

+ + +
+ +
1.3

Motivations

+ + +

Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

+ +

The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may over-ride default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

+ +

Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

+ +

Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

+ +

service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

+ +

service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

+
+
+ +
2

Model

+ + +
2.1

Service Worker

+ +

A service worker is a type of web worker. A service worker executes in the registering service worker client's origin.

+

A service worker has an associated state, which is one of parsed, installing, installed, activating, activated, and redundant. (Initially parsed).

+

A service worker has an associated script url (a URL).

+

A service worker has an associated containing service worker registration (a service worker registration), which contains itself.

+

A service worker is dispatched a set of lifecycle events, install and activate, and functional events including fetch.

+

A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.

+ +
2.1.1

Lifetime

+ +

The lifetime of a service worker is tied to the execution lifetime of events, not references held by service worker clients to the ServiceWorker object. The user agent may terminate service workers at any time it has no event to handle or detects abnormal operation such as infinite loops and tasks exceeding imposed time limits, if any, while handling the events.

+
+
+ +
2.2

Service Worker Registration

+ +

A service worker registration is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. The user agents may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

+

A service worker registration has an associated scope url (a URL).

+

A service worker registration has an associated registering script url (a URL).

+

A service worker registration has an associated installing worker (a service worker) whose state is installing. It is initially set to null.

+

A service worker registration has an associated waiting worker (a service worker) whose state is installed. It is initially set to null.

+

A service worker registration has an associated active worker (a service worker) whose state is either activating or activated. It is initially set to null. An active worker controls a service worker client if the active worker's containing service worker registration's scope url matches the service worker client's creation url upon navigation. When a service worker client is controlled by an active worker, it is considered the service worker client is using the active worker's containing service worker registration.

+

A service worker registration has an associated uninstalling flag. It is initially unset.

+ +
2.2.1

Lifetime

+ +

The user agents must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. The user agent has a scope to registration map that stores the entries of the tuple of service worker registration's scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

+
+
+
2.3

Service Worker Client

+ +

A service worker client is an environment settings object that specifies various settings for its JavaScript global environment. A service worker client independently selects and uses a service worker registration for its own loading and its subresources.

+ +

A service worker client has an associated active worker (an active worker) which currently controls it. It is initially set to null.

+ +

A window client is a service worker client whose global object is a Window object.

+ +

A window client has an associated frame type (a context frame type).

+ +

A dedicated worker client is a service worker client whose global object is a DedicatedWorkerGlobalObject object.

+ +

A shared worker client is a service worker client whose global object is a SharedWorkerGlobalObject object.

+ +

A worker client is either a dedicated worker client or a shared worker client.

+
+
+ +
3

Client Context

+ + +

Example: Bootstrapping with a ServiceWorker

+ +
// scope defaults to "/"
+navigator.serviceWorker.register("/assets/v1/serviceworker.js").then(
+  function(registration) {
+    console.log("success!");
+    if (registration.installing) {
+      registration.installing.postMessage("Howdy from your installing page.");
+    }
+  },
+  function(why) {
+    console.error("Installing the worker failed!:", why);
+  });
+ +
3.1

ServiceWorker

+ + +

+
[Exposed=(Window,Worker)]
+interface ServiceWorker : Worker {
+  readonly attribute USVString scriptURL;
+  readonly attribute ServiceWorkerState state;
+
+  // event
+  attribute EventHandler onstatechange;
+
+  // terminate() method inherited from Worker should not be accessible.
+};
+
+enum ServiceWorkerState {
+  "installing",
+  "installed",
+  "activating",
+  "activated",
+  "redundant"
+};
+ +

A ServiceWorker object represents a service worker. Each ServiceWorker object is associated with a service worker. Multiple separate objects implementing the ServiceWorker interface across document environments and worker environments can all be associated with the same service worker simultaneously.

+ +

A ServiceWorker object has an associated ServiceWorkerState object which is itself associated with service worker's state.

+ +

The terminate() method inherited from Worker, when called on the context object, should throw an "InvalidAccessError" exception.

+ +

The postMessage(message, transfer) method inherited from Worker, when called on the context object, should throw an "InvalidStateError" exception if the state attribute value of the context object is "redundant". Otherwise, it should run a worker, if not running, for a script with its associated service worker serviceWorker's script url and serviceWorker's environment settings object, and run as defined on the Worker interface.

+ +

Communication with these workers is provided via standard HTML5 messaging APIs, and messaging occurs as per usual with Web Workers.

+ +
3.1.1

scriptURL

+ + +

The scriptURL attribute must return service worker's serialized script url.

+ +

For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

+ +
// Script on the page https://example.com/app.html
+navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
+ +

The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

+
+ +
3.1.2

state

+ + +

The state attribute must return the value (in ServiceWorkerState enumeration) corresponding to the first matching statement, switching on service worker's state:

+ +
+
installing
+
"installing" +

The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

+ +
installed
+
"installed" +

The service worker in this state is considered a waiting worker.

+ +
activating
+
"activating" +

The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

+ +
activated
+
"activated" +

The service worker in this state is considered an active worker ready to handle functional events.

+ +
redundant
+
"redundant" +

A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

+
+
+ +
3.1.3

Event handler

+ + +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorker interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onstatechangestatechange
+
+
+ +
3.2

ServiceWorkerRegistration

+ + +
[Exposed=(Window,Worker)]
+interface ServiceWorkerRegistration : EventTarget {
+  [Unforgeable] readonly attribute ServiceWorker? installing;
+  [Unforgeable] readonly attribute ServiceWorker? waiting;
+  [Unforgeable] readonly attribute ServiceWorker? active;
+
+  readonly attribute USVString scope;
+
+  void update();
+  Promise<boolean> unregister();
+
+  // event
+  attribute EventHandler onupdatefound;
+};
+ +

A ServiceWorkerRegistration object represents a service worker registration. Each ServiceWorkerRegistration object is associated with a service worker registration (a service worker registration). Multiple separate objects implementing the ServiceWorkerRegistration interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

+ +

A ServiceWorkerRegistration has an associated service worker client (a service worker client).

+ +
3.2.1
+ + + +
+ +
3.2.2
+ + + +
+ +
3.2.3
+ + + +
+ +
3.2.4

scope

+ + +

The scope attribute must return service worker registration's serialized scope url.

+ +

In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

+
+ +
3.2.5

update()

+ + +

update() pings the server for an updated version of this script without consulting caches. This is conceptually the same operation that UA does maximum once per every 24 hours.

+

update() method must run these steps or their equivalent:

+
+
    +
  1. Invoke Soft Update algorithm, or its equivalent, passing the service worker registration registration as the argument.
  2. +
+
+
+ +
3.2.6
+ + + + + + +
+
    +
  1. Let scopeURL be the scope url of the service worker registration.
  2. +
  3. Return the result of running the Unregister algorithm, or its equivalent, passing the service worker client client, and scopeURL as the arguments.
  4. +
+
+
+ +
3.2.7

Event handler

+ + +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onupdatefoundupdatefound
+
+
+ +
3.3
+ + +
partial interface Navigator {
+  readonly attribute ServiceWorkerContainer serviceWorker;
+};
+
+partial interface WorkerNavigator {
+  readonly attribute ServiceWorkerContainer serviceWorker;
+};
+ + +
+ +
3.4

ServiceWorkerContainer

+ + +
[Exposed=(Window,Worker)]
+interface ServiceWorkerContainer : EventTarget {
+  [Unforgeable] readonly attribute ServiceWorker? controller;
+  readonly attribute Promise<ServiceWorkerRegistration> ready;
+
+  Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
+
+  Promise<ServiceWorkerRegistration> getRegistration(optional USVString clientURL = "");
+  Promise<sequence<ServiceWorkerRegistration>?> getRegistrations();
+
+
+  // events
+  attribute EventHandler oncontrollerchange;
+  attribute EventHandler onerror;
+};
+
+dictionary RegistrationOptions {
+  USVString scope;
+};
+
+ +

A ServiceWorkerContainer provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

+

A ServiceWorkerContainer has an associated service worker client, which is a service worker client whose global object is associated with the Navigator object or the WorkerNavigator object that the ServiceWorkerContainer is retrieved from.

+ +

A ServiceWorkerContainer object has an associated ready promise (a promise). It is initially set to null.

+ +
3.4.1
+ + + + +
+
3.4.2
+ + + +
+
    +
  1. If the context object's ready promise is null, then: +
      +
    1. Set the context object's ready promise to a new promise.
    2. +
    +
  2. +
  3. If the context object's ready promise is settled, then: +
      +
    1. Return the context object's ready promise.
    2. +
    +
  4. +
  5. Let registration be null.
  6. +
  7. Let clientURL be the context object's service worker client's creation url.
  8. +
  9. Run the following substeps in parallel: +
      +
    1. CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
        +
      1. Set registration to the result value.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Wait until scope to registration map has a new entry.
      2. +
      3. Jump to the step labeled CheckRegistration.
      4. +
      +
    4. +
    5. If registration's active worker is null, then: +
        +
      1. Wait until registration's active worker changes.
      2. +
      +

      Implementers should consider this condition is met when the corresponding registration request gets to the step 1.8 of Activate algorithm.

      +
    6. +
    7. Resolve context object's ready promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
    8. +
    +
  10. +
  11. Return context object's ready promise.
  12. +
+
+ +
+ +
3.4.3
+ + + + + +
+
    +
  1. Let scriptURL be the result of parsing scriptURL with entry settings object's API base URL.
  2. +
  3. If scriptURL is failure, return a promise rejected with a TypeError.
  4. +
  5. Let scopeURL be null.
  6. +
  7. If the optional argument options is omitted or options.scope is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

    The scope url for the registration is set to the location of the service worker script by default.

    +
  8. +
  9. Else, set scopeURL to the result of parsing options.scope with entry settings object's API base URL.
  10. +
  11. If scopeURL is failure, return a promise rejected with a TypeError.
  12. +
  13. Return the result of running the Register algorithm, or its equivalent, passing the service worker client client, scriptURL, scopeURL as the arguments.
  14. +
+
+
+ +
3.4.4
+ + + + +
+
    +
  1. Let clientURL be the result of parsing clientURL with entry settings object's API base URL.
  2. +
  3. If clientURL is failure, return a promise rejected with a TypeError.
  4. +
  5. If the origin of clientURL is not the context object's service worker client's origin, return a promise with a "SecurityError" exception.
  6. +
  7. Let promise be a new promise.
  8. +
  9. Run the following substeps in parallel: +
      +
    1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument.
    2. +
    3. If registration is not null, then: +
        +
      1. Resolve promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
      2. +
      +
    4. +
    5. Else: +
        +
      1. Resolve promise with undefined.
      2. +
      +
    6. +
    +
  10. +
  11. Return promise.
  12. +
+
+
+ +
3.4.5
+ + + + + + + +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. Let array be an empty array.
    2. +
    3. For each Record {[[key]], [[value]]} entry of its scope to registration map: +
        +
      1. If the origin of the result of parsing entry.[[key]] is its service worker client's origin, then: +
          +
        1. Add a ServiceWorkerRegistration object, setting its service worker client to service worker client, associated with entry.[[value]] to the array.
        2. +
        +
      2. +
      +
    4. +
    5. Resolve promise with array.
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
3.4.6

Event handlers

+ + +

The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

+ + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oncontrollerchangecontrollerchange
onerrorerror
+
+
+ +
3.5

Events

+ + +

The following events are dispatched on ServiceWorker object:

+ + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
statechangeEventThe state attribute of the ServiceWorker object is changed.
+ +

The following events are dispatched on ServiceWorkerContainer object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
updatefoundEventThe service worker registration's installing worker changes (See step 4.6 of the Install algorithm).
controllerchangeEventThe service worker client's active worker changes. (See step 1.10 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, navigator.serviceWorker.controller immediately reflects the active worker as the service worker that controls the service worker client.)
errorErrorEventAny error occurred from the associated service workers.
+
+
+ +
4

Execution Context

+ + +

Example: Serving Cached Resources

+ +
// caching.js
+this.addEventListener("install", function(e) {
+  e.waitUntil(
+    // Open a cache of resources.
+    caches.open("shell-v1").then(function(cache) {
+      // Begins the process of fetching them.
+      // The coast is only clear when all the resources are ready.
+      return cache.addAll([
+        "/app.html",
+        "/assets/v1/base.css",
+        "/assets/v1/app.js",
+        "/assets/v1/logo.png",
+        "/assets/v1/intro_video.webm"
+      ]);
+    })
+  );
+});
+
+this.addEventListener("fetch", function(e) {
+  // No "fetch" events are dispatched to the service worker until it
+  // successfully installs and activates.
+
+  // All operations on caches are async, including matching URLs, so we use
+  // promises heavily. e.respondWith() even takes promises to enable this:
+  e.respondWith(
+    caches.match(e.request).then(function(response) {
+      return response || e.default();
+    }).catch(function() {
+      return caches.match("/fallback.html");
+    })
+  );
+});
+ +
4.1

ServiceWorkerGlobalScope

+ + +
[Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
+interface ServiceWorkerGlobalScope : WorkerGlobalScope {
+  readonly attribute Cache scriptCache;
+
+  // A container for a list of Client objects that correspond to
+  // browsing contexts (or shared workers) that are on the origin of this SW
+  readonly attribute Clients clients;
+  readonly attribute ServiceWorkerRegistration registration;
+
+  Promise<void> skipWaiting();
+
+  attribute EventHandler oninstall;
+  attribute EventHandler onactivate;
+  attribute EventHandler onfetch;
+  attribute EventHandler onbeforeevicted;
+  attribute EventHandler onevicted;
+
+  // The event.source of these MessageEvents are instances of Client
+  attribute EventHandler onmessage;
+
+  // close() method inherited from WorkerGlobalScope should not be accessible.
+};
+
+ +

A ServiceWorkerGlobalScope object represents the global execution context of a service worker. A ServiceWorkerGlobalScope object has an associated service worker (a service worker).

+

ServiceWorkerGlobalScope object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

+ +

The close() method inherited from WorkerGlobalScope, when called on the context object, should throw an "InvalidAccessError" exception.

+ +
4.1.1

scriptCache

+ + +

scriptCache must return a Cache object that represents the storage for scripts that are cached as part of the service worker installation.

+
+
4.1.2

clients

+ + +

clients attribute must return the Clients object.

+
+
4.1.3

registration

+ + + The registration attribute must return the ServiceWorkerRegistration object that represents the service worker's containing service worker registration.

+
+ +
4.1.4

skipWaiting()

+ + +

The skipWaiting() method allows this service worker to progress from the registration's waiting position to active even while service worker clients are using the registration.

+ +

skipWaiting() method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. Set service worker's skip waiting flag
    2. +
    3. If service worker's state is installed, then: +
        +
      1. Run Activate algorithm, or its equivalent, passing service worker's registration as the argument.
      2. +
      +
    4. +
    5. Resolve promise with undefined.
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
4.1.5

Event handlers

+ + +

The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oninstallinstall
onactivateactivate
onfetchfetch
onbeforeevictedbeforeevicted
onevictedevicted
onmessagemessage
+ +

For onmessage event handler, ServiceWorkerGlobalScope objects act as if they had an implicit MessagePort associated with them. This port is part of a channel that is set up when the service worker is spun off to run, but it is not exposed. This object must never be garbage collected before the ServiceWorkerGlobalScope object. All messages received by that port must immediately be retargeted at the ServiceWorkerGlobalScope object. That is, an event named message using the MessageEvent interface is dispatched on ServiceWorkerGlobalScope object. The event.source of these MessageEvents are instances of Client.

+
+
+
4.2

Client

+ + +
[Exposed=ServiceWorker]
+interface Client {
+  readonly attribute USVString url;
+  void postMessage(any message, optional sequence<Transferable> transfer);
+};
+
+[Exposed=ServiceWorker]
+interface WindowClient : Client {
+  readonly attribute VisibilityState visibilityState;
+  readonly attribute boolean focused;
+  readonly attribute FrameType frameType;
+  Promise<WindowClient> focus();
+};
+
+enum FrameType {
+  "auxiliary",
+  "top-level",
+  "nested",
+  "none"
+};
+
+

A Client object has an associated service worker client (a service worker client).

+ +

A WindowClient object has an associated visibility state, which is one of visibilityState attribute value.

+ +

A WindowClient object has an associated focus state, which is either true or false. (Initially false).

+ +
4.2.1

url

+ + +

The url attribute must return the context object's associated service worker client's serialized creation url.

+
+ +
4.2.2

visibilityState

+ + +

The visibilityState attribute must return the context object's visibility state.

+
+ +
4.2.3

focused

+ + +

The focused attribute must return the context object's focus state.

+
+ +
4.2.4

frameType

+ + +

The frameType attribute must return the value (in FrameType enumeration) corresponding to the first matching statement, switching on service worker client's frame type:

+ +
+
auxiliary
+
"auxiliary" +

The window client's global object's browsing context is an auxiliary browsing context.

+ +
top-level
+
"top-level" +

The window client's global object's browsing context is a top-level browsing context.

+ +
nested
+
"nested" +

The window client's global object's browsing context is a nested browsing context.

+ +
none
+
"none"
+
+
+ +
4.2.5

focus()

+ +

The focus() method must run these steps or their equivalent:

+
+
    +
  1. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run these steps in parallel: +
      +
    1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
    2. +
    3. Queue a task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
        +
      1. Run the focusing steps with browsingContext.
      2. +
      3. Resolve promise with the result of running Capture Window Client algorithm, or its equivalent, with browsingContext as the argument.
      4. +
      +
    4. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+
+
4.3

Clients

+ + +
[Exposed=ServiceWorker]
+interface Clients {
+  // The objects returned will be new instances every time
+  Promise<sequence<Client>?> getAll(optional ClientQueryOptions options);
+  Promise<WindowClient> openWindow(USVString url);
+  Promise<void> claim();
+};
+
+dictionary ClientQueryOptions {
+  boolean includeUncontrolled = false;
+  ClientType type = "window";
+};
+
+enum ClientType {
+  "window",
+  "worker",
+  "sharedworker",
+  "all"
+};
+
+

The Clients interface represents a container for a list of Client objects.

+
4.3.1

getAll(options)

+ +

The getAll(options) method must run these steps or their equivalent:

+
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let clients be an empty array.
    2. +
    3. If the optional argument options is omitted, then: +
        +
      1. For each service worker client client whose active worker is the associated service worker, in the most recently focused order for window clients: +
          +
        1. If client is a window client, then: +
            +
          1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
          2. +
          3. Add windowClient to clients.
          4. +
          +
        2. +
        +
      2. +
      3. Resolve promise with clients.
      4. +
      +
    4. +
    5. Else: +
        +
      1. Let targetClients be an empty array.
      2. +
      3. For each service worker client client whose origin is the same as the associated service worker's origin: +
          +
        1. If options.includeUncontrolled is false, then: +
            +
          1. If client's active worker is the associated service worker, add client to targetClients.
          2. +
          +
        2. +
        3. Else: +
            +
          1. Add client to targetClients.
          2. +
          +
        4. +
        +
      4. +
      5. Let matchedClients be an empty array.
      6. +
      7. For each service worker client client in targetClients, in the most recently focused order for window clients: +
          +
        1. If options.type is "window", and client is a window client, then: +
            +
          1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
          2. +
          3. Add windowClient to matchedClients.
          4. +
          +
        2. +
        3. Else if options.type is "worker" and client is a dedicated worker client, add a Client object that represents client to matchedClients.
        4. +
        5. Else if options.type is "sharedworker" and clientis a shared worker client, add a Client object that represents client to matchedClients.
        6. +
        7. Else if options.type is "all", then: +
            +
          1. If client is a window client, then: +
              +
            1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
            2. +
            3. Add windowClient to matchedClients.
            4. +
            +
          2. +
          3. Else, add a Client object that represents client to matchedClients.
          4. +
          +
        +
      8. +
      9. Resolve promise with matchedClients.
      10. +
      +
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+
4.3.2

openWindow(url)

+ +

The openWindow(url) method must run these steps or their equivalent:

+
+
    +
  1. Let url be the result of parsing url with entry settings object's API base URL.
  2. +
  3. If url is failure, return a promise rejected with a TypeError.
  4. +
  5. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception.
  6. +
  7. Let promise be a new promise.
  8. +
  9. Run these steps in parallel: +
      +
    1. Let newContext be a new top level browsing context.
    2. +
    3. If url is about:blank, then: + +
        +
      1. Queue a task to fire a simple event named load at newContext's Window object, with target override set to newContext's Window object's Document object.
      2. +
      +
    4. Otherwise: +
        +
      1. Navigate newContext to url, with exceptions enabled and replacement enabled.
      2. +
      +
    5. +
    6. If the origin of url is not client's origin, then: +
        +
      1. Resolve promise with null.
      2. +
      3. Abort these steps.
      4. +
      +
    7. +
    8. Let client be the result of running Capture Window Client algorithm, or its equivalent, with newContext as the argument.
    9. +
    10. Resolve promise with client.
    11. +
    +
  10. +
  11. Return promise.
  12. +
+
+
+ +
4.3.3

claim()

+ +

The claim() method must run these steps or their equivalent:

+
+
    +
  1. If the service worker is not an active worker, return a promise rejected with an "InvalidStateError" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run the following substeps in parallel: +
      +
    1. For each service worker client client whose origin is the same as the service worker's origin: +
        +
      1. Let registration be the result of running Match Service Worker Registration algorithm passing client's creation url as the argument.
      2. +
      3. If registration is not the service worker's containing service worker registration, continue to the next iteration of the loop.
      4. +
      5. If client's active worker is not the service worker, then: +
          +
        1. Set client's active worker to service worker.
        2. +
        3. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with.
        4. +
        +
      6. +
      +
    2. +
    3. Resolve promise with undefined.
    4. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+
+ + + +
4.4

ExtendableEvent

+ + +
[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
+interface ExtendableEvent : Event {
+  void waitUntil(Promise<any> f);
+};
+
+dictionary ExtendableEventInit : EventInit {
+  // Defined for the forward compatibility across the derived events
+};
+
+ +

Service workers have two lifecycle events, install and activate. Service workers use the ExtendableEvent interface for activate event and the InstallEvent interface, which inherits from the ExtendableEvent interface, for install event. Service worker extensions that define event handlers may also use the ExtendableEvent interface.

+ +

An ExtendableEvent object has an associated extend lifetime promises (an array of promises). It is initially set to null.

+ +

The service worker should not be terminated until the result of waiting for all of the extend lifetime promises has been settled. However, the user agent may impose a time limit to this lifetime extension.

+ +
4.4.1

event.waitUntil(f)

+ + +

waitUntil(f) method, extends the lifetime of the event. When called in oninstall, it delays treating the installing worker as installed (i.e. a waiting worker) until the passed promise resolves successfully. This is primarily used to ensure that a service worker is not considered installed (i.e. a waiting worker) until all of the core caches it depends on are populated. When called in onactivate, it delays treating the active worker as activated until the passed promise resolves successfully. This is primarily used to ensure that any functional events are not dispatched to the ServiceWorkerGlobalScope object that represents the service worker until it upgrades database schemas and deletes the outdated cache entries. Service worker extensions that define event handlers will define their own behaviours, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

+ +

waitUntil(f) method must run these steps or their equivalent:

+
+
    +
  1. If the active function is not the callback of the event handler whose type is the context object's type value, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. Add f to extend lifetime promises.
  4. +
+
+
+
+ +
4.5

InstallEvent

+ + +
[Constructor(DOMString type, optional InstallEventInit eventInitDict), Exposed=ServiceWorker]
+interface InstallEvent : ExtendableEvent {
+  readonly attribute ServiceWorker? activeWorker;
+};
+
+dictionary InstallEventInit : EventInit {
+  ServiceWorker activeWorker;
+};
+
+
+ +
4.6

FetchEvent

+ + +
[Constructor(DOMString type, optional FetchEventInit eventInitDict), Exposed=ServiceWorker]
+interface FetchEvent : Event {
+  readonly attribute Request request;
+  readonly attribute Client client;
+  readonly attribute boolean isReload;
+
+  void respondWith((Response or Promise<Response>) r);
+  Promise<Response> forwardTo(USVString url);
+  Promise<Response> default();
+};
+
+dictionary FetchEventInit : EventInit {
+  Request request;
+  Client client;
+  boolean isReload;
+};
+
+ +

Each event using FetchEvent interface has the following associated flag that is initially unset: +

    +
  • wait to respond flag
  • +
  • respond-with entered flag
  • +
  • respond-with error flag
  • +
+

+ +
4.6.1

event.respondWith(r)

+ + +

When event.respondWith(r) method is invoked, the argument, r, must resolve with a Response, else a network error is returned to Fetch. If the request is a top-level navigation and the return value is a Response whose type attribute is "opaque" (i.e., an opaque response body), a network error is returned to Fetch. The final URL of all successful (non network-error) responses is the requested URL. Renderer-side security checks about tainting for cross-origin content are tied to the transparency (or opacity) of the Response body, not URLs.

+ +

respondWith(r) method must run these steps or their equivalent:

+
+
    +
  1. If the active function is not the callback of the event handler whose type is fetch, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. If the respond-with entered flag is set, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  4. +
  5. Set the stop propagation flag and stop immediate propagation flag.
  6. +
  7. Set the respond-with entered flag.
  8. +
  9. Set the wait to respond flag.
  10. +
  11. Let responsePromise be null.
  12. +
  13. If r is a Response object, then: +
      +
    1. Set responsePromise to a promise resolved with r.
    2. +
    +
  14. +
  15. Else: +
      +
    1. Set responsePromise to r.
    2. +
    +
  16. +
  17. Run the following substeps in parallel: +
      +
    1. Wait until responsePromise settles.
    2. +
    3. If responsePromise rejected, then: +
        +
      1. Set the respond-with error flag.
      2. +
      +
    4. +
    5. If responsePromise resolved with response, then: +
        +
      1. If response is a Response object, then: +
          +
        1. Let request be the context object's request attribute value.
        2. +
        3. If response.type is "opaque", and request's associated request is a client request, set the respond-with error flag.
        4. +
        5. If response's body is non-null, then: +
            +
          1. If response's used flag is set, set the respond-with error flag.
          2. +
          3. Set response's used flag.
          4. +
          +
        6. +
        +
      2. +
      3. Else: +
          +
        1. Set the respond-with error flag.
        2. +
        +

        If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 19.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 20.1.)

        +
      4. +
      +
    6. + +
    7. Unset the wait to respond flag.
    8. +
    +
  18. +
+
+
+ +
4.6.2

event.default()

+ + +

The invocation of event.default() method performs a fetch using event.request. event.request represents the original request from the controlled service worker client. During the execution, the original request is not altered (except the skip service worker flag), and thus event.default() fetches the original request through the UA's HTTP stack. event.default() returns a promise, which resolves with a Response object, that can be an argument to the event.respondWith(r) method.

+ +

default() method must run these steps or their equivalent:

+
+
    +
  1. If event's dispatch flag is unset, then: +
      +
    1. Return a promise rejected with an "InvalidStateError" exception.
    2. +
    +
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run the following substeps in parallel: +
      +
    1. Let r be the context object's request attribute value.
    2. +
    3. If r's body is non-null, then: +
        +
      1. If r's used flag is set, then: +
          +
        1. Reject promise with a TypeError.
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      3. Set r's used flag.
      4. +
      +
    4. +
    5. Let request be r's associated request.
    6. +
    7. Set request's skip service worker flag and request's synchronous flag.
    8. +
    9. Let response be the result of running fetch with request as its argument.
    10. +
    11. If response is a network error, then: +
        +
      1. Reject promise with a TypeError.
      2. +
      +
    12. +
    13. Else: +
        +
      1. Resolve promise with a new Response object associated with response.
      2. +
      +
    14. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+ +
4.6.3

event.isReload

+ + +

isReload attribute must return true if event was dispatched with the user's intention for the page reload, and false otherwise. Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

+
+
+ +
4.7

Events

+ + +

The following events are dispatched on ServiceWorkerGlobalScope object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
installInstallEvent[Lifecycle event] The service worker's containing service worker registration's installing worker changes. (See step 4.7.3 of the Install algorithm.)
activateExtendableEvent[Lifecycle event] The service worker's containing service worker registration's active worker changes. (See step 1.11.3 of the Activate algorithm.)
fetchFetchEvent[Functional event] Fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the Service Woker returns a response to Fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method or event.default() method. (A custom Response object can be another option.)
+ +

Custom event types for beforeevicted and evicted should be added.

+
+
+ +
5

Caches

+ +

To allow authors to fully manage their content caches for offline use, the Window and the WorkerGlobalScope provide the caching methods largely conforming to ECMAScript 6 Map objects with additional convenience methods. An origin can have multiple, named Cache objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser's HTTP cache.

+ +
5.1

Constructs

+ + +

A fetching record is a Record {[[key]], [[value]]} where [[key]] is a Request and [[value]] is a Response.

+

A fetching record has an associated incumbent record (a fetching record). It is initially set to null.

+

A request to response map is a List of fetching records.

+ +

A name to cache map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a name of the Cache object and [[value]] is a Cache object.

+ +

Each origin has an associated name to cache map.

+
+ +
5.2

Understanding Cache Lifetimes

+ + +

The Cache instances are not part of the browser's HTTP cache. The Cache objects are exactly what authors have to manage themselves. The Cache objects do not get updated unless authors explicitly request them to be. The Cache objects do not expire unless authors delete the entries. The Cache objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

+
+ +
5.3

self.caches

+ +
partial interface Window {
+  readonly attribute CacheStorage caches;
+};
+
+partial interface WorkerGlobalScope {
+  readonly attribute CacheStorage caches;
+};
+
+
5.3.1

caches

+ + +

caches attribute must return a CacheStorage object that represents the name to cache map of the context object's environment settings object's origin.

+
+
+ +
5.4

Cache

+ +
[Exposed=(Window,Worker)]
+interface Cache {
+  Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
+  Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+  Promise<void> add(RequestInfo request);
+  Promise<void> addAll(sequence<RequestInfo> requests);
+  Promise<void> put(RequestInfo request, Response response);
+  Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
+  Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
+};
+
+dictionary CacheQueryOptions {
+  boolean ignoreSearch = false;
+  boolean ignoreMethod = false;
+  boolean ignoreVary = false;
+  boolean prefixMatch = false;
+  DOMString cacheName;
+};
+
+dictionary CacheBatchOperation {
+  DOMString type;
+  Request request;
+  Response response;
+  CacheQueryOptions options;
+};
+
+

A Cache object represents a request to response map. Multiple separate objects implementing the Cache interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

+ +

Cache objects are always enumerable via self.caches in insertion order (per ECMAScript 6 Map objects.)

+ +
5.4.1

match(request, options)

+ + +

match(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let p be the result of running the algorithm specified in matchAll(request, options) method with request and options as the arguments.
    2. +
    3. Wait until p settles.
    4. +
    5. If p rejects with an exception, then: +
        +
      1. Reject promise with that exception.
      2. +
      +
    6. +
    7. Else if p resolves with an array, responseArray, then: +
        +
      1. If responseArray is an empty array, then: +
          +
        1. Resolve promise with undefined.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Resolve promise with the first element of responseArray.
        2. +
        +
      4. +
      +
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
5.4.2

matchAll(request, options)

+ + +

matchAll(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let responseArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add entry.[[value]] to responseArray.
        2. +
        +
      2. +
      3. Resolve promise with responseArray.
      4. +
      5. Abort these steps.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a USVString, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      4. +
      5. Else: +
          +
        1. Set r to request's associated request.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let entries be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments.
      10. +
      11. For each entry of entries: +
          +
        1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, add incumbentRecord.[[value]] to responseArray.
        2. +
        3. Else, add entry[1] to responseArray.
        4. +
        +
      12. +
      13. Resolve promise with responseArray.
      14. +
      +
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
5.4.3

add(request)

+ + +

add(request) method must run these steps or their equivalent:

+ +
+
    +
  1. Let requests be an array containing only request.
  2. +
  3. Set responseArrayPromise to the result of running the algorithm specified in addAll(requests) passing requests as the argument.
  4. +
  5. Let p be transforming responseArrayPromise with onFulfilled.
  6. +
  7. Upon fulfillment of p with value responseArray, perform the following substeps, onFulfilled, in parallel: +
      +
    1. Resolve p with undefined.
    2. +
    +
  8. +
  9. Return p.
  10. +
+
+
+ +
5.4.4

addAll(requests)

+ + +

addAll(requests) method must run these steps or their equivalent:

+ +
+
    +
  1. Let responsePromiseArray be an empty array.
  2. +
  3. Let requestArray be an empty array.
  4. +
  5. For each request in requests: +
      +
    1. Let r be null.
    2. +
    3. If request is a USVString, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
      2. +
      +
    4. +
    5. Else: +
        +
      1. If request's body is non-null, then: +
          +
        1. If request's used flag is set, return a promise rejected with a TypeError.
        2. +
        3. Set request's used flag.
        4. +
        +
      2. +
      3. Set r to request's associated request.
      4. +
      +
    6. +
    7. Set r's url's fragment to null.
    8. +
    9. Add a Request object that represents r to requestArray.
    10. +
    11. If r's url's scheme is not one of "http" and "https", then: +
        +
      1. Add a promise rejected with a "NetworkError" exception to responsePromiseArray.
      2. +
      3. Continue to the next iteration of the loop.
      4. +
      +
    12. +
    13. Let responsePromise be a new promise.
    14. +
    15. Run the following in parallel: +
        +
      • Fetch r.
      • +
      • To process response for response, run these substeps: +
          +
        1. If response's type is error, reject responsePromise with a TypeError.
        2. +
        3. Else, resolve responsePromise with new Response object associated with response.
        4. +
        +

        This step ensures that the promise for this fetch resolves as soon as the response's headers become available.

        +
      • +
      • To process response body for response, do nothing.
      • +
      • To process response end-of-file for response, do nothing.
      • +
      +
    16. +
    17. Add responsePromise to responsePromiseArray.
    18. +
    +
  6. +
  7. Let p be waiting for all of responsePromiseArray.
  8. +
  9. Let q be transforming p with onFulfilled.
  10. +
  11. Upon fulfillment of p with value responseArray, perform the following substeps, onFulfilled, in parallel: +
      +
    1. Let operations be an empty array.
    2. +
    3. For each response in responseArray with the index index: +
        +
      1. If response's body is non-null, then: +
          +
        1. If response's used flag is set, reject q with a TypeError.
        2. +
        3. Set response's used flag.
        4. +
        +
      2. +
      3. Let o be an empty object representing a CacheBatchOperation dictionary.
      4. +
      5. Set the type dictionary member of o to "put".
      6. +
      7. Set the request dictionary member of o to requestArray[index].
      8. +
      9. Set the response dictionary member of o to response.
      10. +
      11. Add o to operations.
      12. +
      +
    4. +
    5. Let resultPromise to the result of running Batch Cache Operations algorithm passing operations as the argument.
    6. +
    7. Upon fulfillment of resultPromise with value responses, perform the following substeps, onFulfilled, in parallel: +
        +
      1. For each response in responses: +
          +
        1. Let responseBodyPromise be a new promise.
        2. +
        3. Run the following substeps in parallel: +
            +
          1. Wait for either end-of-file to have been pushed to response's associated response r's body or for r to have a termination reason.
          2. +
          3. If r had a termination reason, then: +
              +
            1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
                +
              1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
              2. +
              +
            2. +
            3. Else: +
                +
              1. Delete fetchingRecord from request to response map.
              2. +
              +
            4. +
            5. Reject responseBodyPromise with a TypeError.
            6. +
            +
          4. +
          5. Else: +
              +
            1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
            2. +
            3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
            4. +
            5. For each invalidRecord in invalidRecords: +
                +
              1. If invalidRecord is not fetchingRecord, delete it from request to response map.
              2. +
              +
            6. +
            7. Resolve responseBodyPromise with response.
            8. +
            +
          6. +
          +
        4. +
        5. Add responseBodyPromise to responseBodyPromiseArray.
        6. +
        +
      2. +
      3. Upon fulfillment of waiting for all of responseBodyPromiseArray, resolve q with undefined.
      4. +
      +
    8. +
    +
  12. +
  13. Return q.
  14. +
+
+
+ +
5.4.5

put(request, response)

+ + +

put(request, response) method must run these steps or their equivalent:

+ +
+
    +
  1. Let r be null.
  2. +
  3. If request is a USVString, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    +
  4. +
  5. Else: +
      +
    1. If request's body is non-null, then: +
        +
      1. If request's used flag is set, return a promise rejected with a TypeError.
      2. +
      3. Set request's used flag.
      4. +
      +
    2. +
    3. Set r to request's associated request.
    4. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. If response's body is non-null, then: +
      +
    1. If response's used flag is set, return a promise rejected with a TypeError.
    2. +
    3. Set response's used flag.
    4. +
    +
  10. +
  11. Let operations be an empty array.
  12. +
  13. Let o be an empty object representing a CacheBatchOperation dictionary.
  14. +
  15. Set the type dictionary member of o to "put".
  16. +
  17. Set the request dictionary member of o to a Request object that represents r.
  18. +
  19. Set the response dictionary member of o to response.
  20. +
  21. Add o to operations.
  22. +
  23. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
  24. +
  25. Let p be transforming resultPromise with onFulfilled.
  26. +
  27. Upon fulfillment of resultPromise with value responses, perform the following substeps, onFulfilled, in parallel: +
      +
    1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r's body or for r to have a termination reason.
    2. +
    3. If r had a termination reason, then: +
        +
      1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
          +
        1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Delete fetchingRecord from request to response map.
        2. +
        +
      4. +
      5. Reject p with a TypeError.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
      2. +
      3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
      4. +
      5. For each invalidRecord in invalidRecords: +
          +
        1. If invalidRecord is not fetchingRecord, delete it from request to response map.
        2. +
        +
      6. +
      7. Resolve p with undefined.
      8. +
      +
    6. +
    +
  28. +
  29. Return p.
  30. +
+
+
+ +
5.4.6

delete(request, options)

+ + +

delete(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let r be null.
  2. +
  3. If request is a USVString, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    +
  4. +
  5. Else: +
      +
    1. Set r to request's associated request.
    2. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. Let operations be an empty array.
  10. +
  11. Let o be an empty object representing a CacheBatchOperation dictionary.
  12. +
  13. Set the type dictionary member of o to "delete".
  14. +
  15. Set the request dictionary member of o to a Request object that represents r.
  16. +
  17. Set the options dictionary member of o to options.
  18. +
  19. Add o to operations.
  20. +
  21. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
  22. +
  23. Let p be transforming resultPromise with onFulfilled.
  24. +
  25. Upon fulfillment of p with responseArray, perform the following substeps, onFulfilled, in parallel: +
      +
    1. If responseArray is not null, then: +
        +
      1. Resolve p with true.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Resolve p with false.
      2. +
      +
    4. +
    +
  26. +
  27. Return p.
  28. +
+
+
+ +
5.4.7

keys(request, options)

+ + +

keys(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let resultArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add entry.[[key]] to resultArray.
        2. +
        +
      2. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a USVString, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      4. +
      5. Else: +
          +
        1. Set r to request's associated request.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let requestResponseArray be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments.
      10. +
      11. For each requestResponse in requestResponseArray: +
          +
        1. Add requestResponse[0] to resultArray.
        2. +
        +
      12. +
      +
    6. +
    7. Resolve promise with resultArray.
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+
+ +
5.5

CacheStorage

+ + +
[Exposed=(Window,Worker)]
+interface CacheStorage {
+  Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
+  Promise<boolean> has(DOMString cacheName);
+  Promise<Cache> open(DOMString cacheName);
+  Promise<boolean> delete(DOMString cacheName);
+  Promise<sequence<DOMString>> keys();
+};
+ + +

CacheStorage interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

+ +

A CacheStorage object represents a name to cache map. Multiple separate objects implementing the CacheStorage interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

+ +
5.5.1

match(request, options)

+ + +

match(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let cacheName be null.
  2. +
  3. If the optional argument options is not omitted, then: +
      +
    1. Set cacheName to options.cacheName.
    2. +
    +
  4. +
  5. If cacheName is not null, then: +
      +
    1. Return a promise, p, resolved with the result of running the following substeps: +
        +
      1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. If cacheName matches entry.[[key]], then: +
            +
          1. Resolve p with the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).)
          2. +
          3. Abort these steps.
          4. +
          +
        2. +
        +
      2. +
      3. Reject p with an "NotFoundError" exception.
      4. +
      +
    2. +
    +
  6. +
  7. Else: +
      +
    1. Set p to transforming the result of running the algorithm specified in keys() method, with onFulfilled.
    2. +
    3. Upon fulfillment of p with value keys, perform the following substeps, onFulfilled, in parallel: +
        +
      1. For each key in keys: +
          +
        1. Let q be the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing key as thisArgument to the [[Call]] internal method of match(request, options).)
        2. +
        3. Upon fulfillment of q with value matchedResponse: +
            +
          1. If matchedResponse is not undefined, then: +
              +
            1. Resolve p with matchedResponse.
            2. +
            3. Abort these steps.
            4. +
            +
          2. +
          +
        4. +
        5. Upon rejection of q with value err: +
            +
          1. Reject p with err.
          2. +
          3. Abort these steps.
          4. +
          +
        6. +
        +
      2. +
      3. Resolve p with undefined.
      4. +
      +
    4. +
    5. Return p.
    6. +
    +
  8. +
+
+
+ +
5.5.2

has(cacheName)

+ + +

has(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. Return a promise, p, resolved with the result of running the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.[[key]], then: +
          +
        1. Return true.
        2. +
        +
      2. +
      +
    2. +
    3. Return false.
    4. +
    +
  2. +
+
+
+ +
5.5.3

open(cacheName)

+ + +

open(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. Return a promise, p, resolved with the result of running the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.[[key]], then: +
          +
        1. Return a new Cache object which is a copy of entry.[[value]].
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      +
    2. +
    3. Let cache be a new Cache object.
    4. +
    5. Set a newly-created Record {[[key]]: cacheName, [[value]]: cache} to name to cache map.
    6. +
    7. Return cache.
    8. +
    +
  2. +
+
+
+ +
5.5.4

delete(cacheName)

+ + +

delete(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. Let p be the result of running the algorithm specified in has(cacheName) method with cacheName as the argument.
  2. +
  3. Let q be transforming p with onFulfilled.
  4. +
  5. Upon fulfillment of p with value cacheExists, perform the following substeps, onFulfilled, in parallel: +
      +
    1. If cacheExists is true, then: +
        +
      1. Delete a Record {[[key]], [[value]]} entry of its name to cache map where cacheName matches entry.[[key]].
      2. +
      3. Resolve q with true.
      4. +
      5. Abort these steps.
      6. +
      +
    2. +
    3. Else: +
        +
      1. Resolve q with flase.
      2. +
      +
    4. +
    +
  6. +
  7. Return q.
  8. +
+
+
+ +
5.5.5

keys()

+ + +

keys() method must run these steps or their equivalent:

+ +

The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

+ +
+
    +
  1. Let resultArray be an empty array.
  2. +
  3. Return a promise, p, resolved with the result of running the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. Add entry.[[key]] to resultArray.
      2. +
      +
    2. +
    3. Return resultArray.
    4. +
    +
  4. +
+
+
+
+
+ +
6

Security Considerations

+ + +

Service workers should be implemented to be HTTPS-only. The reasons for SSL-only support include:

+ + +

The section will be updated.

+ +
6.1

Origin Relativity

+ + +

One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

+

The section will be updated.

+
+ +
6.2

Cross-Origin Resources and CORS

+ + +

Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to XHR many sorts of off-origin resources when appropriate CORS headers are set.

+

ServiceWorkers enable this by allowing Caches to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the Cache as Response objects with the type attribute set to "basic", the objects stored are Response objects with the type attribute set to "opaque". Responses typed "opaque" provide a much less expressive API than Responses typed "basic"; the bodies and headers cannot be read or set, nor many of the other aspects of their content inspected. They can be passed to event.respondWith(r) method and event.forwardTo(url) method in the same manner as the Responses typed "basic", but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Caches to store them allows applications to avoid re-architecting in most cases.

+

The section will be updated.

+
+
+ +
7

Storage Considerations

+ + +

Service workers should take a dependency on Quota Management in preparation for an extension event that communicates storage pressure and pre-eviction information to the application.

+

The section will be updated.

+
+ +
8

Extensibility

+ + +

Service workers are extensible from other specifications.

+ +
8.1

Define API bound to Service Worker Registration

+ +

Specifications may define an API tied to a service worker registration by using partial interface definition to the ServiceWorkerRegistration interface where it may define the specification specific attributes and methods:

+ +
partial interface ServiceWorkerRegistration {
+  // e.g. define an API namespace
+  readonly attribute APISpaceType APISpace;
+  // e.g. define a method
+  Promise<T> methodName(list of arguments);
+};
+
+
+ +
8.2

Define Functional Event

+ +

Specifications may define a functional event by extending ExtendableEvent interface:

+ +
// e.g. define FunctionalEvent interface
+interface FunctionalEvent : ExtendableEvent {
+  // add a functional event's own attributes and methods
+};
+
+
+ +
8.3

Define Event Handler

+ +

Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the ServiceWorkerGlobalScope interface:

+ +
partial interface ServiceWorkerGlobalScope {
+  attribute EventHandler onfunctionalevent;
+};
+
+ +
8.4

Request Functional Event Dispatch

+ +

To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

+ +

Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a ServiceWorkerGlobalScope object) at which it may fire its functional events. This algorithm is called on a task run by Handle Functional Event On Scheduled Task algorithm which is queued by Handle Functional Event algorithm.

+ +

See an example hook defined in Notifications API.

+
+
+ +
9

Appendix A: Algorithms

+ + +

The following definitions are the user agent's internal data structures used throughout the specification.

+ +

A scope to registration map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a scope url and [[value]] is a service worker registration.

+ +

An algorithm thread queue is a thread safe queue used to synchronize the set of concurrent entries of algorithm steps. The queue contains timestamps (with the assumptions), gained by algorithms, as its elements. The queue should satisfy the general properties of FIFO queue.

+ +

A registration queue is an algorithm thread queue for synchronizing the set of concurrent registration requests. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +

An installation queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +

An installation result handle queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +
9.1

Register

+ + +
+
+
Input
+
client, a service worker client
+
scriptURL, an absolute URL
+
scopeURL, an absolute URL
+
Output
+
promise, a promise
+
+
    +
  1. If the result of running Is origin potentially trustworthy with the origin of scriptURL as the argument is Not Trusted, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  2. +
  3. If the origin of scriptURL is not client's origin, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  4. +
  5. If the origin of scopeURL is not client's origin, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  6. +
  7. Run the following substeps atomically: +
      +
    1. Let registration be the result of running the Get Registration algorithm passing scopeURL as the argument.
    2. + +
    3. If registration is not null, then: +
        +
      1. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
      2. +
      3. If newestWorker is not null, scriptURL is equal to newestWorker's script url, and scriptURL is equal to registration's registering script url, then: +
          +
        1. If newestWorker is an active worker, then: +
            +
          1. If registration's uninstalling flag is set, unset it.
          2. +
          3. Return a promise resolved with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
          4. +
          +
        2. +
        +
      4. +
      +
    4. +
    5. Else: +
        +
      1. Set registration to the result of running Set Registration algorithm passing scopeURL as its argument.
      2. +
      +
    6. +
    7. Set registration's registering script url to scriptURL.
    8. +
    9. Return the result of running the Update algorithm, or its equivalent, passing client and registration as the argument.
    10. +
    +
  8. +
+
+
+ +
9.2

Update

+ + +

The algorithm uses registration queue to synchronize the set of multiple registration requests. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

+ + +
+
+
Input
+
client, a service worker client
+
registration, a service worker registration
+
Output
+
promise, a promise
+
+
    +
  1. Let p be a new promise.
  2. +
  3. Generate a timestamp and let timeStamp be the result value.
  4. +
  5. Push timeStamp to registration queue, installation queue, and installation result handle queue.
  6. +
  7. Run the following substeps in parallel: +
      +
    1. CheckPriority: If the value of the top element of registration queue matches timeStamp, then: +
        +
      1. Pop the top element from registration queue.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Wait until the top element of registration queue is popped.
      2. +
      3. Jump to the step labeled CheckProirity.
      4. +
      +

      Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

      +
    4. +
    5. Run the following substeps atomically: +
        +
      1. If registration's installing worker is not null, then: +
          +
        1. Terminate registration's installing worker.
        2. +
        3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
        4. +
        5. Set registration's installing worker to null.
        6. +
        7. The user agent may abort in-flight requests triggered by registration's installing worker.
        8. +
        +
      2. +
      3. Let r be the associated request of the result of invoking the initial value of Request as constructor with registration's registering script url. If this throws an exception, then: +
          +
        1. Reject p with the exception.
        2. +
        3. Pop the top element from installation queue and installation result handle queue.
        4. +
        5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
        6. +
        7. Abort these steps.
        8. +
        +
      4. +
      5. Set r's context to serviceworker.
      6. +
      7. Append `Service-Worker`/`script` to r's header list.
      8. +
      9. Set r's skip service worker flag and r's synchronous flag.
      10. +
      11. Let response be the result of running fetch using r, forcing a network fetch if cached entry is greater than 1 day old.
      12. +
      13. If response is a network error, then: +
          +
        1. If r's redirect count is not zero, then: +
            +
          1. Reject p with a "SecurityError" exception.
          2. +
          3. Pop the top element from installation queue and installation result handle queue.
          4. +
          5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
          6. +
          7. Abort these steps.
          8. +
          +
        2. +
        3. Else: +
            +
          1. Reject p with a "NetworkError" exception.
          2. +
          3. Pop the top element from installation queue and installation result handle queue.
          4. +
          5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
          6. +
          7. Abort these steps.
          8. +
          +
        4. +
        +
      14. +
      15. Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
          +
        1. Reject p with a "SecurityError" exception.
        2. +
        3. Pop the top element from installation queue and installation result handle queue.
        4. +
        5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
        6. +
        7. Abort these steps.
        8. +
        +
      16. +
      17. Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response's header list.
      18. +
      19. If serviceWorkerAllowed is failure, then: +
          +
        1. Reject p with a "SecurityError" exception.
        2. +
        3. Pop the top element from installation queue and installation result handle queue.
        4. +
        5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
        6. +
        7. Abort these steps.
        8. +
        +
      20. +
      21. Let scopeURL be registration's scope url.
      22. +
      23. Let maxScopeString be null.
      24. +
      25. If serviceWorkerAllowed is null, then: +
          +
        1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script's file name, in registration's registering script url's path (including empty strings), separated from each other by "/".
        2. +
        +
      26. +
      27. Else: +
          +
        1. Let maxScope be the result of parsing serviceWorkerAllowed with registration's registering script url.
        2. +
        3. Set maxScopeString to "/" concatenated with the strings in maxScope's path (including empty strings), separated from each other by "/".
        4. +
        +
      28. +
      29. Let scopeString be "/" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/".
      30. +
      31. If scopeString starts with maxScopeString, do nothing.
      32. +
      33. Else: +
          +
        1. Reject p with a "SecurityError" exception.
        2. +
        3. Pop the top element from installation queue and installation result handle queue.
        4. +
        5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
        6. +
        7. Abort these steps.
        8. +
        +
      34. +
      35. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
      36. +
      37. If newestWorker is not null, and newestWorker's script url is equal to registration's registering script url and response is a byte-for-byte match with the script of newestWorker, then: +
          +
        1. Resolve p with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
        2. +
        3. Abort these steps.
        4. +
        +
      38. +
      39. Else: +
          +
        1. Let worker be a new service worker for the script with registration's registering script url.
        2. +
        3. If worker fails to start up, due to parse errors or uncaught errors, then: +
            +
          1. Reject p with the error.
          2. +
          3. Pop the top element from installation queue and installation result handle queue.
          4. +
          5. If the result of running Get Newest Worker algorithm is null, then: +
              +
            1. Invoke Clear Registration algorithm passing registration as its argument.
            2. +
            +
          6. +
          7. Abort these steps.
          8. +
          +
        4. +
        +
      40. +
      +
    6. +
    7. Invoke Install algorithm, or its equivalent, with client, registration, worker, p, and timeStamp as its arguments.
    8. +
    +
  8. +
  9. Return p.
  10. +
+
+
+ +
9.3

Soft Update

+ + +

The user agent may call this as often as it likes to check for updates.

+ +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Let client be an empty environment settings object.
  2. +
  3. If registration's uninstalling flag is set, then: +
      +
    1. Abort these steps.
    2. +
    +
  4. +
  5. If registration's installing worker is not null, then: +
      +
    1. Abort these steps.
    2. +
    +
  6. +
  7. Invoke Update algorithm, or its equivalent, with client, registration as its argument.
  8. +
+
+

Inspect whether the promise returned from Update algorithm should be returned to the caller (either UA internal context or reg.update()).

+
+ +
9.4

Install

+ + +

The algorithm uses installation queue to synchronize the set of multiple installation jobs. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

+ +
+
+
Input
+
client, a service worker client
+
registration, a service worker registration
+
worker, a service worker
+
registrationPromise, a promise
+
timeStamp, a timestamp
+
Output
+
none
+
+
    +
  1. Let installFailed be false.
  2. +
  3. CheckPriority: If the value of the top element of installation queue matches timeStamp, then: +
      +
    1. Pop the top element from installation queue.
    2. +
    +
  4. +
  5. Else: +
      +
    1. Wait until the top element of installation queue is popped.
    2. +
    3. Jump to the step labeled CheckProirity.
    4. +
    +

    Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

    +
  6. +
  7. Run the following substeps atomically: +
      +
    1. If registration's installing worker is not null, then: +
        +
      1. Terminate registration's installing worker.
      2. +
      3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      4. +
      5. The user agent may abort any in-flight requests triggered by registration's installing worker.
      6. +
      +
    2. +
    3. Set registration's installing worker to worker.
    4. +
    5. Run the Update State algorithm passing registration's installing worker and installing as the arguments.
    6. +
    7. Assert: registrationPromise is not null.
    8. +
    9. Resolve registrationPromise with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
    10. +
    11. Queue a task to fire a simple event named updatefound at all the ServiceWorkerRegistration objects that represent registration for all the service worker clients whose creation url matches registration's scope url.
    12. +
    13. Queue a task to run the following substeps: +
        +
      1. Let installingWorker be registration's installing worker.
      2. +
      3. Run a worker, if not running, for a script with installingWorker's script url and installingWorker's environment settings object.
      4. +
      5. Fire an event named install using InstallEvent interface at installingWorker's environment settings object's global object.
      6. +
      7. Let event be null.
      8. +
      9. For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling.
          2. +
          3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
          4. +
          5. Set registration's installing worker to null.
          6. +
          7. Pop the top element from installation result handle queue.
          8. +
          9. If the result of running Get Newest Worker algorithm is null, then: +
              +
            1. Invoke Clear Registration algorithm passing registration as its argument.
            2. +
            +
          10. +
          11. Abort these steps.
          12. +
          +
        2. +
        3. Set event to the event for which this event listener was invoked.
        4. +
        +
      10. +
      11. Let p be waiting for all of event's extend lifetime promises.
      12. +
      13. Wait until p settles.
      14. +
      15. If p rejected, then: +
          +
        1. Set installFailed to true.
        2. +
        +
      16. +
      17. Else if p resolved with a value, then: +
          +
        1. Do nothing.
        2. +
        +
      18. +
      +
    14. +
    +
  8. +
  9. CheckResultHandlePriority: If the value of the top element of installation result handle queue matches timeStamp, then: +
      +
    1. Pop the top element from installation result handle queue.
    2. +
    +
  10. +
  11. Else: +
      +
    1. Wait until the top element of installation result handle queue is popped.
    2. +
    3. Jump to the step labeled CheckResultHandlePriority.
    4. +
    +

    Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

    +
  12. +
  13. Run the following substeps atomically: +
      +
    1. Wait for the task queued by the step 4.7 to have executed.
    2. +
    3. If registration's installing worker is null, then: +
        +
      1. Abort these steps.
      2. +
      +
    4. +
    5. If installFailed is true, then: +
        +
      1. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      2. +
      3. Set registration's installing worker to null.
      4. +
      5. If the result of running Get Newest Worker algorithm is null, then: +
          +
        1. Invoke Clear Registration algorithm passing registration as its argument.
        2. +
        +
      6. +
      7. Abort these steps.
      8. +
      +
    6. +
    7. If registration's waiting worker is not null, then: +
        +
      1. Terminate registration's waiting worker.
      2. +
      3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
      4. +
      5. The user agent may abort in-flight requests triggered by registration's waiting worker.
      6. +
      +
    8. +
    9. Set registration's waiting worker to registration's installing worker.
    10. +
    11. Set registration's installing worker to null.
    12. +
    13. Run the Update State algorithm passing registration's waiting worker and installed as the arguments.
    14. +
    15. If registration's uninstalling flag is set before timeStamp, then: +
        +
      1. Wait until a Record {[[key]], [[value]]} entry of its scope to registration map where registration's scope url matches entry.[[key]] is deleted.
      2. +
      3. Set a newly-created Record {[[key]]: registration's scope url, [[value]]: registration} to scope to registration map.
      4. +
      5. Unset registration's uninstalling flag.
      6. +
      +
    16. +
    17. If registration's waiting worker's skip waiting flag is set, then: +
        +
      1. For each service worker client serviceWorkerClient whose creation url matches registration's scope url: +
          +
        1. Let exitingWorker be the active worker that controls serviceWorkerClient.
        2. +
        3. If exitingWorker is not null, then: +
            +
          1. Wait for exitingWorker to finish handling any in-progress requests. +
          2. +
          3. Terminate exitingWorker.
          4. +
          5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
          6. +
          +
        4. +
        +
      2. +
      3. Run Activate algorithm, or its equivalent, passing registration as the argument.
      4. +
      5. Abort these steps.
      6. +
      +
    18. +
    +
  14. +
  15. Wait until no service worker client is using registration or registration's waiting worker's skip waiting flag is set.
  16. +
  17. If registration's waiting worker waitingWorker is not null and waitingWorker's skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument.
  18. +
+
+
+ +
9.5

Activate

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Run the following substeps atomically: +
      +
    1. Let activateFailed be false.
    2. +
    3. Let activatingWorker be registration's waiting worker.
    4. +
    5. Let exitingWorker be registration's active worker.
    6. +
    7. If activatingWorker is null, then: +
        +
      1. Abort these steps.
      2. +
      +
    8. +
    9. If exitingWorker is not null, then: +
        +
      1. Wait for exitingWorker to finish handling any in-progress requests. +
      2. +
      3. Terminate exitingWorker.
      4. +
      5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
      6. +
      +
    10. +
    11. Set registration's active worker to activatingWorker.
    12. +
    13. Set registration's waiting worker to null.
    14. +
    15. Run the Update State algorithm passing registration's active worker and activating as the arguments.
    16. +
    17. For each service worker client client whose creation url matches registration's scope url: +
        +
      1. If client is a window client, then: +
          +
        1. Unassociate client's responsible document from its application cache, if it has one.
        2. +
        +
      2. +
      3. Else if client is a shared worker client, then: +
          +
        1. Unassociate client's global object from its application cache, if it has one.
        2. +
        +
      4. +
      +

      Resources will now use the service worker registration instead of the existing application cache.

      +
    18. +
    19. Queue a task to fire a simple event named controllerchange at all the ServiceWorkerContainer objects for all the service worker clients which use registration.
    20. +
    21. Queue a task to run the following substeps: +
        +
      1. Let activeWorker be registration's active worker.
      2. +
      3. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
      4. +
      5. Fire an event named activate using ExtendableEvent interface at activeWorker's environment settings object's global object.
      6. +
      7. Let event be null.
      8. +
      9. For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling.
          2. +
          3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
          4. +
          5. Set registration's active worker to null.
          6. +
          7. Abort these steps.
          8. +
          +
        2. +
        3. Set event to the event for which this event listener was invoked.
        4. +
        +
      10. +
      11. Let p be waiting for all of event's extend lifetime promises.
      12. +
      13. Wait until p settles.
      14. +
      15. If p rejected, then: +
          +
        1. Set activateFailed to true.
        2. +
        +
      16. +
      17. Else if p resolved with a value, then: +
          +
        1. Do nothing.
        2. +
        +
      18. +
      +
    22. +
    23. Wait for the task queued by the previous step to have executed.
    24. +
    25. If activateFailed is true, then: +
        +
      1. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
      2. +
      3. Set registration's active worker to null.
      4. +
      5. Abort these steps.
      6. +
      +
    26. +
    27. Run the Update State algorithm passing registration's active worker and activated as the arguments.
    28. +
    +
  2. +
+
+
+ +
9.6

Handle Fetch

+ + +

The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

+ +
+
+
Input
+
request, a request
+
Output
+
response, a response
+
+
    +
  1. Let handleFetchFailed be false.
  2. +
  3. Let respondWithEntered be false.
  4. +
  5. Let eventCanceled be false.
  6. +
  7. Let r be a new Request object associated with request.
  8. +
  9. Let headersObject be r's headers attribute value.
  10. +
  11. Set headersObject's guard to immutable.
  12. +
  13. Let response be null.
  14. +
  15. Let registration be null.
  16. +
  17. Let client be request's client.
  18. +
  19. Assert: request's context is not serviceworker.
  20. +
  21. If request is a potential client request, then: +
      +
    1. Return null.
    2. +
    +
  22. +
  23. Else if request is a client request, then: +
      +
    1. If the navigation triggering request was initiated with a shift+reload or equivalent, then: +
        +
      1. Return null.
      2. +
      +
    2. +
    3. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing r's url attribute value as the argument.
    4. +
    5. If registration is null or registration's active worker is null, return null.
    6. +
    7. Set client's active worker to registration's active worker.
    8. +
    +

    From this point, the service worker client starts to use its active worker's containing service worker registration.

    +
  24. +
  25. Else if request is a resource request, then: +
      +
    1. If client's active worker in non-null, then: +
        +
      1. Set registration to client's active worker's containing service worker registration.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Return null.
      2. +
      +
    4. +
    +
  26. +
  27. Let matchedWorker be registration's active worker.
  28. +
  29. If matchedWorker's state is activating, then: +
      +
    1. Wait for matchedWorker's state to become activated.
    2. +
    3. If matchedWorker's activation fails, then: +
        +
      1. Return null.
      2. +
      +
    4. +
    +
  30. +
  31. Queue a task to run the following substeps: +
      +
    1. Let activeWorker be registration's active worker.
    2. +
    3. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
    4. +
    5. Fire an event named fetch, using FetchEvent interface, with request attribute initialized to r, client attribute initialized to client of the request, in the form of Client object, and isReload initialized to true if event was dispatched with the user's intention for the page reload, and false otherwise, at activeWorker's environment settings object's global object.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      3. Let event be the event for which this event listener was invoked.
      4. +
      5. If event's respond-with entered flag is set, then: +
          +
        1. Set respondWithEntered to true.
        2. +
        +
      6. +
      7. If event's wait to respond flag is set, then: +
          +
        1. Wait until event's wait to respond flag is unset.
        2. +
        3. If event's respond-with error flag is set, then: +
            +
          1. Set handleFetchFailed to true.
          2. +
          +
        4. +
        5. Else: +
            +
          1. If the argument passed into the event's respondWith(r) method arg is a Response object, then: +
            1. Set response to arg.
            +
          2. +
          3. Else: +
              +
            1. Set response to the value which arg resolved with.
            2. +
            +
          4. +
          +
        6. +
        +
      8. +
      9. If event's canceled flag is set, then: +
          +
        1. Set eventCanceled to true.
        2. +
        +
      10. +
      +
    8. +
    +
  32. +
  33. Wait for the task queued by the previous step to have executed.
  34. +
  35. If respondWithEntered is false, then: +
      +
    1. If eventCanceled is true, then: +
        +
      1. Return a network error and run the following substeps in parallel.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Return null and run the following substeps in parallel.
      2. +
      +
    4. +
    5. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    6. +
    7. Abort these steps.
    8. +
    +
  36. +
  37. If handleFetchFailed is true, then: +
      +
    1. Return a network error and run the following substeps in parallel.
    2. +
    3. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    4. +
    +
  38. +
  39. Else: +
      +
    1. Return a response represented by response and run the following substeps in parallel.
    2. +
    3. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    4. +
    +
  40. +
+
+
+ +
9.7

Handle Functional Event

+ + +
+
+
Input
+
registration, a service worker registration
+
callbackSteps, an algorithm
+
Output
+
None
+
+
    +
  1. Queue a task to run Handle Functional Event On Scheduled Task algorithm, or its equivalent, with registration and callbackSteps.
  2. +
+
+

Event loop and task queuing model for this algorithm will be specified.

+
+ +
9.8

Handle Functional Event On Scheduled Task

+ + +
+
+
Input
+
registration, a service worker registration
+
callbackSteps, an algorithm
+
Output
+
None
+
+
    +
  1. Assert: a Record with the [[value]] equals to registration is contained in scope to registration map.
  2. +
  3. Assert: registration's active worker is not null.
  4. +
  5. Let activeWorker be registration's active worker.
  6. +
  7. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
  8. +
  9. Invoke callbackSteps, defined by the caller of the algorithm which queued this task, with activeWorker's environment settings object's global object as its argument.
  10. +
  11. Return.
  12. +
+
+
+ +
9.9

Handle Service Worker Client Unload

+ + +

The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

+ +
+
+
Input
+
client, a service worker client
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be the service worker registration used by client.
  4. +
  5. If registration is null, then: +
      +
    1. Abort these steps.
    2. +
    +
  6. +
  7. If any other service worker client is using registration, then: +
      +
    1. Abort these steps.
    2. +
    +
  8. +
  9. If registration's uninstalling flag is true, then: +
      +
    1. Invoke Clear Registration algorithm passing registration as its argument.
    2. +
    3. Abort these steps.
    4. +
    +
  10. +
  11. If registration.waiting is not null: +
      +
    1. Run Activate algorithm, or its equivalent, with registration at the argument.
    2. +
    +
  12. +
+
+
+ +
9.10

Unregister

+ + +
+
+
Input
+
client, a service worker client
+
scope, an absolute URL
+
Output
+
promise, a promise
+
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. If the origin of scope is not client's origin, then: +
        +
      1. Reject promise with a "SecurityError" exception.
      2. +
      3. Abort these steps.
      4. +
      +
    2. +
    3. Let registration be the result of running Get Registration algorithm passing scope as the argument.
    4. +
    5. If registration is null, then: +
        +
      1. Resolve promise with false.
      2. +
      3. Abort these steps.
      4. +
      +
    6. +
    7. Set registration's uninstalling flag.
    8. +
    9. Resolve promise with true.
    10. +
    11. If no service worker client is using registration, then: +
        +
      1. If registration's uninstalling flag is unset, then: +
          +
        1. Abort these steps.
        2. +
        +
      2. +
      3. Invoke Clear Registration algorithm passing registration as its argument.
      4. +
      +
    12. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
9.11

Set Registration

+ + +
+
+
Input
+
scope, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let scopeString be serialized scope with the exclude fragment flag set.
  4. +
  5. Let registration be a new service worker registration whose scope url is set to scope.
  6. +
  7. Set a newly-created Record {[[key]]: scopeString, [[value]]: registration} to scope to registration map.
  8. +
  9. Return registration.
  10. +
+
+
+ +
9.12

Clear Registration

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. If registration's installing worker is not null, then: +
      +
    1. Terminate registration's installing worker.
    2. +
    3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    4. +
    5. Set registration's installing worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's installing worker.
    8. +
    +
  4. +
  5. If registration's waiting worker is not null, then: +
      +
    1. Terminate registration's waiting worker.
    2. +
    3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
    4. +
    5. Set registration's waiting worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's waiting worker.
    8. +
    +
  6. +
  7. If registration's active worker is not null, then: +
      +
    1. Terminate registration's active worker.
    2. +
    3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
    4. +
    5. Set registration's active worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's active worker.
    8. +
    +
  8. +
  9. Delete a Record {[[key]], [[value]]} entry of its scope to registration map where registration's scope url matches entry.[[key]].
  10. +
+
+
+ +
9.13

Update State

+ + +
+
+
Input
+
worker, a service worker
+
state, a service worker's state
+
Output
+
None
+
+
    +
  1. Set worker's state to state.
  2. +
  3. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker for all the browsing contexts' Document objects and the ServiceWorkerGlobalScope object represented by worker.
  4. +
  5. For each serviceWorker in serviceWorkers: +
      +
    1. Queue a task to fire a simple event named statechange at serviceWorker.
    2. +
    +
  6. +
+
+
+ +
9.14

Match Service Worker Registration

+ + +
+
+
Input
+
clientURL, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let clientURLString be serialized clientURL.
  4. +
  5. Let matchingScope be the longest [[key]] in scope to registration map starting with the value of clientURLString.
  6. +
  7. Let matchingScopeURL be the result of parsing matchingScope.
  8. +
  9. Let registration be the result of running Get Registration algorithm passing matchingScopeURL as the argument.
  10. +
  11. If registration is not null and registration's uninstalling flag is set, then: +
      +
    1. Return null.
    2. +
    +
  12. +
  13. Return registration.
  14. +
+
+
+ +
9.15

Get Registration

+ + +
+
+
Input
+
scope, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be null.
  4. +
  5. Let scopeString be serialized scope with the exclude fragment flag set.
  6. +
  7. For each Record {[[key]], [[value]]} entry of its scope to registration map: +
      +
    1. If scopeString matches entry.[[key]], then: +
        +
      1. Set registration to entry.[[value]].
      2. +
      +
    2. +
    +
  8. +
  9. Return registration.
  10. +
+
+
+ +
9.16

Get Newest Worker

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
worker, a service worker
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let newestWorker be null.
  4. +
  5. If registration's installing worker is not null, then: +
      +
    1. Set newestWorker to registration's installing worker.
    2. +
    +
  6. +
  7. Else if registration's waiting worker is not null, then: +
      +
    1. Set newestWorker to registration's waiting worker.
    2. +
    +
  8. +
  9. Else if registration's active worker is not null, then: +
      +
    1. Set newestWorker to registration's active worker.
    2. +
    +
  10. +
  11. Return newestWorker.
  12. +
+
+
+ +
9.17

Capture Window Client

+ + +
+
+
Input
+
browsingContext, a browsing context
+
Output
+
windowClient, a WindowClient object
+
+
    +
  1. Let windowClient be a new WindowClient object representing browsingContext.
  2. +
  3. Set windowClient's visibility state to browsingContext's active document's visibilityState attribute value.
  4. +
  5. Set windowClient's focus state to the result of running browsingContext's active document's hasFocus() method.
  6. +
  7. Return windowClient.
  8. +
+
+
+ +
9.18

Query Cache

+ + +
+
+
Input
+
request, a Request object
+
options, a CacheQueryOptions object, optional
+
targetStorage, an array that has [Request, Response] pairs as its elements, optional
+
Output
+
resultArray, an array that has [Request, Response] pairs as its elements
+
+
    +
  1. Let requestArray be an empty array.
  2. +
  3. Let responseArray be an empty array.
  4. +
  5. Let resultArray be an empty array.
  6. +
  7. If options.ignoreMethod is false and request.method is neither "GET" nor "HEAD", then: +
      +
    1. Return resultArray.
    2. +
    +
  8. +
  9. Let cachedURL and requestURL be null.
  10. +
  11. Let serializedCachedURL and serializedRequestURL be null.
  12. +
  13. If the optional argument targetStorage is omitted, then: +
      +
    1. For each fetching record entry of its request to response map, in key insertion order: +
        +
      1. Set cachedURL to entry.[[key]]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.ignoreSearch is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If options.prefixMatch is true, then: +
          +
        1. Set serializedCachedURL to the substring of itself from the start, with the length of serializedRequestURL.
        2. +
        +
      12. +
      13. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add entry.[[key]] to requestArray.
        2. +
        3. Add entry.[[value]] to responseArray.
        4. +
        +
      14. +
      +
    2. +
    +
  14. +
  15. Else: +
      +
    1. For each record in targetStorage: +
        +
      1. Set cachedURL to record[0]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.ignoreSearch is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If options.prefixMatch is true, then: +
          +
        1. Set serializedCachedURL to the substring of itself from the start, with the length of serializedRequestURL.
        2. +
        +
      12. +
      13. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add record[0] to requestArray.
        2. +
        3. Add record[1] to responseArray.
        4. +
        +
      14. +
      +
    2. +
    +
  16. +
  17. For each cachedResponse in responseArray with the index index: +
      +
    1. Let cachedRequest be the indexth element in requestArray.
    2. +
    3. If the result of running cachedResponse.headers object's has(name) method with "Vary" as the argument is false, or options.ignoreVary is true, then: +
        +
      1. Add an array [cachedRequest, cachedResponse] to resultArray.
      2. +
      3. Continue to the next iteration of the loop.
      4. +
      +
    4. +
    5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
    6. +
    7. Let matchFailed be false.
    8. +
    9. For each f in varyHeaders: +
        +
      1. If f matches "*", then: +
          +
        1. Continue to the next iteration of the loop.
        2. +
        +
      2. +
      3. If the result of running cachedRequest.headers object's get(name) method with f as the argument does not match the result of running request.headers object's get(name) method with f as the argument, then: +
          +
        1. Set matchFailed to true.
        2. +
        3. Break the loop.
        4. +
        +
      4. +
      +
    10. +
    11. If matchFailed is false, then: +
        +
      1. Add an array [cachedRequest, cachedResponse] to resultArray.
      2. +
      +
    12. +
    +
  18. +
  19. Return resultArray.
  20. +
+
+
+ +
9.19

Batch Cache Operations

+ + +
+
+
Input
+
operations, an array of CacheBatchOperation dictionary objects
+
Output
+
q, a promise resolves with an array of Response objects.
+
+
    +
  1. Let p be a promise resolved with no value.
  2. +
  3. Let q be transforming p with onFulfilled.
  4. +
  5. Upon fulfillment of p with value v, perform the following substeps, onFulfilled, in parallel: +
      +
    1. Let itemsCopy be a new request to response map that is a copy of its context object's request to response map.
    2. +
    3. Let addedRecords be an empty array.
    4. +
    5. Try running the following substeps atomically: +
        +
      1. Let resultArray be an empty array.
      2. +
      3. For each operation in operations with the index index: +
          +
        1. If operation.type matches neither "delete" nor "put", then: +
            +
          1. Throw a TypeError.
          2. +
          +
        2. +
        3. If operation.type matches "delete" and operation.response is not null, then: +
            +
          1. Throw a TypeError.
          2. +
          +
        4. +
        5. If the result of running Query Cache algorithm passing operation.request, operation.options, and addedRecords as the arguments is not an empty array, then: +
            +
          1. Throw an "InvalidStateError" exception.
          2. +
          +
        6. +
        7. Let requestResponseArray be the result of running Query Cache algorithm passing operation.request and operation.options as the arguments.
        8. +
        9. For each requestResponse in requestResponseArray: +
            +
          1. If operation.type matches "delete", remove the corresponding fetching record from request to response map.
          2. +
          +
        10. +
        11. If operation.type matches "put", then: +
            +
          1. If operation.response is null, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          2. +
          3. Let r be operation.request's associated request.
          4. +
          5. If r's url's scheme is not one of "http" and "https", then: +
              +
            1. Throw a TypeError.
            2. +
            +
          6. +
          7. If r's method is not `GET`, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          8. +
          9. If operation.options is not null, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          10. +
          11. If there exists a corresponding fetching record fetchingRecord for operation.request and operation.response in request to response map, set fetchingRecord.[[value]] to operation.response.
          12. +
          13. Else, set a newly-created fetching record {[[key]]: operation.request, [[value]]: operation.response} to request to response map. +

            The cache commit is allowed as long as the response's headers are available.

            +
          14. +
          15. Add an array [operation.request, operation.response] to addedRecords.
          16. +
          +
        12. +
        13. Add operation.response to resultArray.
        14. +
        +
      4. +
      5. Resolve q with resultArray.
      6. +
      +
    6. +
    7. And then, if an exception was thrown, then: +
        +
      1. Set the context object's request to response map to itemsCopy.
      2. +
      3. Reject q with the exception
      4. +
      +
    8. +
    +
  6. +
  7. Return q.
  8. +
+
+
+ +
+ +
10

Acknowledgements

+ + + +

Jake Archibald is a ghost-author of this document. The best instincts in the design are his. He similarly shaped many of the details through discussion and experimentation. The bits which are not his (but which are good) owe everything to his experience, persistence, and focus on enabling web developers. He embodies a hopeful example for developers in shaping browser efforts to more directly address real-world pain points. If service workers solve "offline for the web", the credit is due him.

+ +

Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

+ +

Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.

+ +

In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, and Ben Kelly.

+ +

Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

+ +

The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

+ +

Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, and Wonsuk Lee for their considerable professional support.

+
+ + + diff --git a/publish/service_worker/WD-service-workers-20150625/index.html b/publish/service_worker/WD-service-workers-20150625/index.html new file mode 100644 index 00000000..ca18eb50 --- /dev/null +++ b/publish/service_worker/WD-service-workers-20150625/index.html @@ -0,0 +1,3835 @@ + + + Service Workers + + + + + + + + + + + +
+ + + + +

Service Workers

+

W3C Working Draft 25 June 2015

+
+
This version
+
http://www.w3.org/TR/2015/WD-service-workers-20150625/
+
Latest published version
+
http://www.w3.org/TR/service-workers/
+
Latest editor's draft
+
https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
+
Previous version
+
http://www.w3.org/TR/2015/WD-service-workers-20150205/
+
Revision history
+
https://github.com/slightlyoff/ServiceWorker/commits/master
+
Participate
+
Discuss on public-webapps@w3.org (Web Applications Working Group)
+
File bugs
+
Editors
+
Alex Russell, Google, <>
+
Jungkee Song, Samsung Electronics, <>
+
Jake Archibald, Google, <>
+
+ + + +
+
+ +

Abstract

+ +

This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.

+ +

The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.

+ +

The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.

+ +

Status of This Document

+ +

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

+ +

This document was published by the Web Applications Working Group as a Working Draft. If you wish to make comments regarding this document, please send them to public-webapps@w3.org (subscribe, archives). All feedback is welcome.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

+ +

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

+ +

This document is governed by the 1 August 2014 W3C Process Document.

+ + + +
1

Introduction

+ + +
1.1

About this Document

+ + +

All diagrams, examples, notes, are non-normative, as well as sections explicitly marked as non-normative. Everything else in this specification is normative.

+ +

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification.

+ +

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementers, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

+
+ +
1.2

Dependencies

+ + +

This document relies on the following specifications:

+ + +
+ +
1.3

Motivations

+ + +

Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

+ +

The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may over-ride default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

+ +

Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

+ +

Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

+ +

Service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

+ +

Service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

+
+
+ +
2

Model

+ + +
2.1

Service Worker

+ +

A service worker is a type of web worker. A service worker executes in the registering service worker client's origin.

+

A service worker has an associated state, which is one of parsed, installing, installed, activating, activated, and redundant. (Initially parsed).

+

A service worker has an associated script url (a URL).

+

A service worker has an associated containing service worker registration (a service worker registration), which contains itself.

+

A service worker has an associated id (a UUID), which uniquely identifies itself during the lifetime of its containing service worker registration.

+

A service worker is dispatched a set of lifecycle events, install and activate, and functional events including fetch.

+

A service worker has an associated script resource map which is a List of the Record {[[key]], [[value]]} where [[key]] is a URL and [[value]] is a script resource.

+

A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.

+

A service worker has an associated imported scripts updated flag. It is initially unset.

+ +
2.1.1

Lifetime

+ +

The lifetime of a service worker is tied to the execution lifetime of events, not references held by service worker clients to the ServiceWorker object. The user agent may terminate service workers at any time it has no event to handle or detects abnormal operation such as infinite loops and tasks exceeding imposed time limits, if any, while handling the events.

+
+
+ +
2.2

Service Worker Registration

+ +

A service worker registration is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. The user agents may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

+

A service worker registration has an associated scope url (a URL).

+

A service worker registration has an associated registering script url (a URL).

+

A service worker registration has an associated installing worker (a service worker) whose state is installing. It is initially set to null.

+

A service worker registration has an associated waiting worker (a service worker) whose state is installed. It is initially set to null.

+

A service worker registration has an associated active worker (a service worker) whose state is either activating or activated. It is initially set to null. An active worker controls a service worker client if the active worker's containing service worker registration's scope url matches the service worker client's creation url upon navigation. When a service worker client is controlled by an active worker, it is considered the service worker client is using the active worker's containing service worker registration.

+

A service worker registration has an associated uninstalling flag. It is initially unset.

+ +
2.2.1

Lifetime

+ +

The user agents must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. The user agent has a scope to registration map that stores the entries of the tuple of service worker registration's scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

+
+
+
2.3

Service Worker Client

+ +

A service worker client is an environment settings object that specifies various settings for its JavaScript global environment. A service worker client independently selects and uses a service worker registration for its own loading and its subresources.

+ +

A service worker client has an associated active worker (an active worker) which currently controls it. It is initially set to null.

+ +

A service worker client has an associated id (a UUID), which uniquely identifies itself during its lifetime. It is initially set to a new UUID when the corresponding environment settings object that it represents is created.

+ +

A window client is a service worker client whose global object is a Window object.

+ +

A window client has an associated frame type (a context frame type).

+ +

A dedicated worker client is a service worker client whose global object is a DedicatedWorkerGlobalObject object.

+ +

A shared worker client is a service worker client whose global object is a SharedWorkerGlobalObject object.

+ +

A worker client is either a dedicated worker client or a shared worker client.

+
+
+ +
3

Client Context

+ + +

Example: Bootstrapping with a ServiceWorker

+ +
// scope defaults to the path the script sits in
+// "/" in this example
+navigator.serviceWorker.register("/serviceworker.js").then(
+  function(registration) {
+    console.log("success!");
+    if (registration.installing) {
+      registration.installing.postMessage("Howdy from your installing page.");
+    }
+  },
+  function(why) {
+    console.error("Installing the worker failed!:", why);
+  });
+ +
3.1

ServiceWorker

+ + +

+
[Exposed=(Window,Worker)]
+interface ServiceWorker : EventTarget {
+  readonly attribute USVString scriptURL;
+  readonly attribute ServiceWorkerState state;
+  readonly attribute DOMString id;
+  void postMessage(any message, optional sequence<Transferable> transfer);
+
+  // event
+  attribute EventHandler onstatechange;
+};
+ServiceWorker implements AbstractWorker;
+
+enum ServiceWorkerState {
+  "installing",
+  "installed",
+  "activating",
+  "activated",
+  "redundant"
+};
+ +

A ServiceWorker object represents a service worker. Each ServiceWorker object is associated with a service worker. Multiple separate objects implementing the ServiceWorker interface across document environments and worker environments can all be associated with the same service worker simultaneously.

+ +

A ServiceWorker object has an associated ServiceWorkerState object which is itself associated with service worker's state.

+ +

A ServiceWorker object has an associated service worker client (a service worker client).

+ +
3.1.1

scriptURL

+ + +

The scriptURL attribute must return the service worker's serialized script url.

+ +

For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

+ +
// Script on the page https://example.com/app.html
+navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
+ +

The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

+
+ +
3.1.2

state

+ + +

The state attribute must return the value (in ServiceWorkerState enumeration) corresponding to the first matching statement, switching on the service worker's state:

+ +
+
installing
+
"installing" +

The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

+ +
installed
+
"installed" +

The service worker in this state is considered a waiting worker.

+ +
activating
+
"activating" +

The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

+ +
activated
+
"activated" +

The service worker in this state is considered an active worker ready to handle functional events.

+ +
redundant
+
"redundant" +

A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

+
+
+ +
3.1.3

id

+ + +

The id attribute must return the service worker's id.

+
+ +
3.1.4

postMessage(message, transfer)

+ + +

The postMessage(message, transfer) method must run these steps or their equivalent:

+
+
    +
  1. If the state attribute value of the context object is "redundant", throw an "InvalidStateError" exception and abort these steps.
  2. +
  3. Let newPorts be an empty array.
  4. +
  5. Let transferMap be an empty association list of Transferable objects to placeholder objects.
  6. +
  7. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps.
    2. +
    3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts.
    4. +
    +
  8. +
  9. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
  10. +
  11. Let serviceWorker be the service worker represented by the context object.
  12. +
  13. Invoke Run Service Worker algorithm with serviceWorker as the arguement.
  14. +
  15. Let destination be the ServiceWorkerGlobalScope object associated with serviceWorker.
  16. +
  17. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. Let newOwner be the destination's environment settings object.
    2. +
    3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
    4. +
    +
  18. +
  19. Make newPorts into a read only array.
  20. +
  21. Queue a task that runs the following steps: +
      +
    1. Create an event e that uses the ExtendableMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Let the data attribute of e be initialized to clonedMessage.
    4. +
    5. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
    6. +
    7. If the global object globalObject specified by the incumbent settings object is a ServiceWorkerGlobalScope object, let the source attribute of e be initialized to a new ServiceWorker object that represents globalObject's service worker.
    8. +
    9. Else if globalObject is a Window object, let the source attribute of e be initialized to a new WindowClient object that represents globalObject's browsing context.
    10. +
    11. Else, let it be initialized to a new Client object that represents globalObject's worker environment.
    12. +
    13. Let the ports attribute of e be initialized to newPorts.
    14. +
    15. Dispatch e at destination.
    16. +
    +

    The task must use the DOM manipulation task source.

    +
  22. +
+
+
+ +
3.1.5

Event handler

+ + +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorker interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onstatechangestatechange
+
+
+ +
3.2

ServiceWorkerRegistration

+ + +
[Exposed=(Window,Worker)]
+interface ServiceWorkerRegistration : EventTarget {
+  [Unforgeable, SameObject] readonly attribute ServiceWorker? installing;
+  [Unforgeable, SameObject] readonly attribute ServiceWorker? waiting;
+  [Unforgeable, SameObject] readonly attribute ServiceWorker? active;
+
+  readonly attribute USVString scope;
+
+  void update();
+  [NewObject] Promise<boolean> unregister();
+
+  // event
+  attribute EventHandler onupdatefound;
+};
+ +

A ServiceWorkerRegistration object represents a service worker registration. Each ServiceWorkerRegistration object is associated with a service worker registration (a service worker registration). Multiple separate objects implementing the ServiceWorkerRegistration interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

+ +

A ServiceWorkerRegistration object has an associated service worker client (a service worker client).

+ +
3.2.1
+ + + + +
+
    +
  1. Let installingWorker be a ServiceWorker object that represents the service worker registration's installing worker.
  2. +
  3. Set installingWorker's service worker client to the service worker client.
  4. +
  5. Return installingWorker.
  6. +
+
+
+ +
3.2.2
+ + + + +
+
    +
  1. Let waitingWorker be a ServiceWorker object that represents the service worker registration's waiting worker.
  2. +
  3. Set waitingWorker's service worker client to the service worker client.
  4. +
  5. Return waitingWorker.
  6. +
+
+
+ +
3.2.3
+ + + + +
+
    +
  1. Let activeWorker be a ServiceWorker object that represents the service worker registration's active worker.
  2. +
  3. Set activeWorker's service worker client to the service worker client.
  4. +
  5. Return activeWorker.
  6. +
+
+
+ +
3.2.4

scope

+ + +

The scope attribute must return service worker registration's serialized scope url.

+ +

In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

+
+ +
3.2.5

update()

+ + +

update() pings the server for an updated version of this script without consulting caches. This is conceptually the same operation that UA does maximum once per every 24 hours.

+

update() method must run these steps or their equivalent:

+
+
    +
  1. Let registration be the service worker registration.
  2. +
  3. If registration's uninstalling flag is set, abort these steps.
  4. +
  5. If registration's installing worker is not null, abort these steps.
  6. +
  7. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
  8. +
  9. If newestWorker is null, abort these steps.
  10. +
  11. Set registration's registering script url to newestWorker's script url.
  12. +
  13. Invoke Update algorithm, or its equivalent, passing the service worker client client and registration as the arguments.
  14. +
+
+
+ +
3.2.6
+ + + + + + +
+
    +
  1. Let scopeURL be the scope url of the service worker registration.
  2. +
  3. Return the result of running the Unregister algorithm, or its equivalent, passing the service worker client client, and scopeURL as the arguments.
  4. +
+
+
+ +
3.2.7

Event handler

+ + +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onupdatefoundupdatefound
+
+
+ +
3.3
+ + +
partial interface Navigator {
+  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
+};
+
+partial interface WorkerNavigator {
+  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
+};
+ + +
+ +
3.4

ServiceWorkerContainer

+ + +
[Exposed=(Window,Worker)]
+interface ServiceWorkerContainer : EventTarget {
+  [Unforgeable, SameObject] readonly attribute ServiceWorker? controller;
+  [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
+
+  [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
+
+  [NewObject] Promise<ServiceWorkerRegistration> getRegistration(optional USVString clientURL = "");
+  [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
+
+
+  // events
+  attribute EventHandler oncontrollerchange;
+  attribute EventHandler onerror;
+  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
+};
+
+dictionary RegistrationOptions {
+  USVString scope;
+};
+
+ +

A ServiceWorkerContainer provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

+

A ServiceWorkerContainer has an associated service worker client, which is a service worker client whose global object is associated with the Navigator object or the WorkerNavigator object that the ServiceWorkerContainer is retrieved from.

+ +

A ServiceWorkerContainer object has an associated ready promise (a promise). It is initially set to null.

+ +
3.4.1
+ + + + +
+
3.4.2
+ + + +
+
    +
  1. If the context object's ready promise is null, then: +
      +
    1. Set the context object's ready promise to a new promise.
    2. +
    +
  2. +
  3. If the context object's ready promise is settled, then: +
      +
    1. Return the context object's ready promise.
    2. +
    +
  4. +
  5. Let registration be null.
  6. +
  7. Let clientURL be the context object's service worker client's creation url.
  8. +
  9. Run the following substeps in parallel: +
      +
    1. CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
        +
      1. Set registration to the result value.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Wait until scope to registration map has a new entry.
      2. +
      3. Jump to the step labeled CheckRegistration.
      4. +
      +
    4. +
    5. If registration's active worker is null, then: +
        +
      1. Wait until registration's active worker changes.
      2. +
      +

      Implementers should consider this condition is met when the corresponding registration request gets to the step 10 of Activate algorithm.

      +
    6. +
    7. Resolve context object's ready promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
    8. +
    +
  10. +
  11. Return context object's ready promise.
  12. +
+
+ +
+ +
3.4.3
+ + + + + +
+
    +
  1. Let scriptURL be the result of parsing scriptURL with entry settings object's API base URL.
  2. +
  3. If scriptURL is failure, return a promise rejected with a TypeError.
  4. +
  5. Let scopeURL be null.
  6. +
  7. If the optional argument options is omitted or options.scope is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

    The scope url for the registration is set to the location of the service worker script by default.

    +
  8. +
  9. Else, set scopeURL to the result of parsing options.scope with entry settings object's API base URL.
  10. +
  11. If scopeURL is failure, return a promise rejected with a TypeError.
  12. +
  13. Return the result of running the Register algorithm, or its equivalent, passing the service worker client client, scriptURL, scopeURL as the arguments.
  14. +
+
+
+ +
3.4.4
+ + + + +
+
    +
  1. Let clientURL be the result of parsing clientURL with entry settings object's API base URL.
  2. +
  3. If clientURL is failure, return a promise rejected with a TypeError.
  4. +
  5. If the origin of clientURL is not the context object's service worker client's origin, return a promise with a "SecurityError" exception.
  6. +
  7. Let promise be a new promise.
  8. +
  9. Run the following substeps in parallel: +
      +
    1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument.
    2. +
    3. If registration is not null, then: +
        +
      1. Resolve promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
      2. +
      +
    4. +
    5. Else: +
        +
      1. Resolve promise with undefined.
      2. +
      +
    6. +
    +
  10. +
  11. Return promise.
  12. +
+
+
+ +
3.4.5
+ + + + +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. Let array be an empty array.
    2. +
    3. For each Record {[[key]], [[value]]} entry of its scope to registration map: +
        +
      1. If the origin of the result of parsing entry.[[key]] is its service worker client's origin, then: +
          +
        1. Add a ServiceWorkerRegistration object, setting its service worker client to service worker client, associated with entry.[[value]] to the array.
        2. +
        +
      2. +
      +
    4. +
    5. Resolve promise with array.
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
3.4.6

Event handlers

+ + +

The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

+ + + + + + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oncontrollerchangecontrollerchange
onerrorerror
onmessagemessage
+
+
+ +
3.5

ServiceWorkerMessageEvent

+ + +
[Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
+interface ServiceWorkerMessageEvent : Event {
+  readonly attribute any data;
+  readonly attribute DOMString origin;
+  readonly attribute DOMString lastEventId;
+  [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
+  [SameObject] readonly attribute MessagePort[]? ports;
+};
+
+dictionary ServiceWorkerMessageEventInit : EventInit {
+  any data;
+  DOMString origin;
+  DOMString lastEventId;
+  (ServiceWorker or MessagePort)? source;
+  sequence<MessagePort> ports;
+};
+
+

Service workers define the message event that extends the message event defined in HTML to allow setting a ServiceWorker object as the source of the message. For the message event, service workers use the ServiceWorkerMessageEvent interface.

+ +
3.5.1

event.data

+ +

The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

+
+ +
3.5.2

event.origin

+ +

The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker's environment settings object from which the message is sent.

+
+ +
3.5.3

event.lastEventId

+ +

The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

+
+ +
3.5.4

event.source

+ +

The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the ServiceWorker object whose associated service worker the message is sent from.

+ +

When navigator.connect() API extends the service worker communication model, this attribute may also represent ServicePort object from which the message is sent.

+
+ +
3.5.5

event.ports

+ +

The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

+
+
+ +
3.6

Events

+ + +

The following event is dispatched on ServiceWorker object:

+ + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
statechangeEventThe state attribute of the ServiceWorker object is changed.
+ +

The following event is dispatched on ServiceWorkerRegistration object:

+ + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
updatefoundEventThe service worker registration's installing worker changes. (See step 8 of the Install algorithm).
+ +

The following events are dispatched on ServiceWorkerContainer object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
controllerchangeEventThe service worker client's active worker changes. (See step 12.2 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, navigator.serviceWorker.controller immediately reflects the active worker as the service worker that controls the service worker client.)
messageServiceWorkerMessageEventWhen it receives a message.
errorErrorEventAny error occurred from the associated service workers.
+
+
+ +
4

Execution Context

+ + +

Example: Serving Cached Resources

+ +
// caching.js
+this.addEventListener("install", function(e) {
+  e.waitUntil(
+    // Open a cache of resources.
+    caches.open("shell-v1").then(function(cache) {
+      // Begins the process of fetching them.
+      // The coast is only clear when all the resources are ready.
+      return cache.addAll([
+        "/app.html",
+        "/assets/v1/base.css",
+        "/assets/v1/app.js",
+        "/assets/v1/logo.png",
+        "/assets/v1/intro_video.webm"
+      ]);
+    })
+  );
+});
+
+this.addEventListener("fetch", function(e) {
+  // No "fetch" events are dispatched to the service worker until it
+  // successfully installs and activates.
+
+  // All operations on caches are async, including matching URLs, so we use
+  // promises heavily. e.respondWith() even takes promises to enable this:
+  e.respondWith(
+    caches.match(e.request).then(function(response) {
+      return response || fetch(e.request);
+    }).catch(function() {
+      return caches.match("/fallback.html");
+    })
+  );
+});
+ +
4.1

ServiceWorkerGlobalScope

+ + +
[Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
+interface ServiceWorkerGlobalScope : WorkerGlobalScope {
+  // A container for a list of Client objects that correspond to
+  // browsing contexts (or shared workers) that are on the origin of this SW
+  [SameObject] readonly attribute Clients clients;
+  [SameObject] readonly attribute ServiceWorkerRegistration registration;
+
+  [NewObject] Promise<void> skipWaiting();
+
+  attribute EventHandler oninstall;
+  attribute EventHandler onactivate;
+  attribute EventHandler onfetch;
+
+  // event
+  attribute EventHandler onmessage; // event.source of the message events is Client object
+
+  // close() method inherited from WorkerGlobalScope should not be accessible.
+};
+
+ +

A ServiceWorkerGlobalScope object represents the global execution context of a service worker. A ServiceWorkerGlobalScope object has an associated service worker (a service worker).

+

ServiceWorkerGlobalScope object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

+ +

The close() method inherited from WorkerGlobalScope, when called on the context object, should throw an "InvalidAccessError" exception.

+ +
4.1.1

clients

+ + +

clients attribute must return the Clients object.

+
+
4.1.2

registration

+ + + The registration attribute must return the ServiceWorkerRegistration object that represents the service worker's containing service worker registration.

+
+ +
4.1.3

skipWaiting()

+ + +

The skipWaiting() method allows this service worker to progress from the registration's waiting position to active even while service worker clients are using the registration.

+ +

skipWaiting() method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. Set service worker's skip waiting flag
    2. +
    3. If service worker's state is installed, then: +
        +
      1. Run Activate algorithm, or its equivalent, passing service worker's registration as the argument.
      2. +
      +
    4. +
    5. Resolve promise with undefined.
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
4.1.4

Event handlers

+ + +

The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oninstallinstall
onactivateactivate
onfetchfetch
onmessagemessage
+
+
+
4.2

Client

+ + +
[Exposed=ServiceWorker]
+interface Client {
+  readonly attribute USVString url;
+  readonly attribute FrameType frameType;
+  readonly attribute DOMString id;
+  void postMessage(any message, optional sequence<Transferable> transfer);
+};
+
+[Exposed=ServiceWorker]
+interface WindowClient : Client {
+  readonly attribute VisibilityState visibilityState;
+  readonly attribute boolean focused;
+  [NewObject] Promise<WindowClient> focus();
+  [NewObject] Promise<WindowClient> navigate(USVString url);
+};
+
+enum FrameType {
+  "auxiliary",
+  "top-level",
+  "nested",
+  "none"
+};
+
+

A Client object has an associated service worker client (a service worker client).

+ +

A WindowClient object has an associated visibility state, which is one of visibilityState attribute value.

+ +

A WindowClient object has an associated focus state, which is either true or false. (Initially false).

+ +
4.2.1

url

+ + +

The url attribute must return the context object's associated service worker client's serialized creation url.

+
+ +
4.2.2

frameType

+ + +

The frameType attribute must return the value (in FrameType enumeration) corresponding to the first matching statement, switching on service worker client's frame type:

+ +
+
auxiliary
+
"auxiliary" +

The window client's global object's browsing context is an auxiliary browsing context.

+ +
top-level
+
"top-level" +

The window client's global object's browsing context is a top-level browsing context.

+ +
nested
+
"nested" +

The window client's global object's browsing context is a nested browsing context.

+ +
none
+
"none"
+
+
+ +
4.2.3

id

+ + +

The id attribute must return its associated service worker client's id.

+
+ +
4.2.4

postMessage(message, transfer)

+ + +

The postMessage(message, transfer) method must run these steps or their equivalent:

+
+
    +
  1. Let newPorts be an empty array.
  2. +
  3. Let transferMap be an empty association list of Transferable objects to placeholder objects.
  4. +
  5. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps.
    2. +
    3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts.
    4. +
    +
  6. +
  7. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
  8. +
  9. Let destination be the ServiceWorkerContainer object whose service worker client is the context object's service worker client.
  10. +
  11. If destination is null, throw an "InvalidStateError" exception.
  12. +
  13. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. Let newOwner be the destination's service worker client.
    2. +
    3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
    4. +
    +
  14. +
  15. Make newPorts into a read only array.
  16. +
  17. Queue a task that runs the following steps: +
      +
    1. Create an event e that uses the ServiceWorkerMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Let the data attribute of e be initialized to clonedMessage.
    4. +
    5. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
    6. +
    7. Let the source attribute of e be initialized to a ServiceWorker object, setting its service worker client to destination's service worker client, which represents the service worker associated with the global object specified by the incumbent settings object.
    8. +
    9. Let the ports attribute of e be initialized to newPorts.
    10. +
    11. Dispatch e at destination.
    12. +
    +

    The task must use the DOM manipulation task source, and, for those where the event loop specified by the target ServiceWorkerContainer object's service worker client is a browsing context event loop, must be associated with the responsible document specified by that target ServiceWorkerContainer object's service worker client.

    +
  18. +
+
+
+ +
4.2.5

visibilityState

+ + +

The visibilityState attribute must return the context object's visibility state.

+
+ +
4.2.6

focused

+ + +

The focused attribute must return the context object's focus state.

+
+ +
4.2.7

focus()

+ +

The focus() method must run these steps or their equivalent:

+
+
    +
  1. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run these steps in parallel: +
      +
    1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
    2. +
    3. Queue a task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
        +
      1. Run the focusing steps with browsingContext.
      2. +
      3. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with browsingContext as the argument.
      4. +
      5. If windowClient's focus state is true, resolve promise with windowClient.
      6. +
      7. Else, reject promise with a TypeError.
      8. +
      +
    4. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+ +
4.2.8

navigate(url)

+ +

The navigate() method must run these steps or their equivalent:

+
+
    +
  1. Let url be the result of parsing url with entry settings object's API base URL.
  2. +
  3. If url is failure, return a promise rejected with a TypeError.
  4. +
  5. If url is about:blank, return a promise rejected with a TypeError.
  6. +
  7. If the context object's associated service worker client's active worker is not the incumbent settings object's global object's service worker, return a promise rejected with a TypeError.
  8. +
  9. Let promise be a new promise.
  10. +
  11. Run these steps in parallel: +
      +
    1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
    2. +
    3. If browsingContext has discarded its Document, reject promise with a TypeError and abort these steps.
    4. +
    5. Queue a task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
        +
      1. Navigate browsingContext to url with replacement enabled and exceptions enabled. The source browsing context must be browsingContext.
      2. +
      3. If the navigation throws an exception, reject promise with that exception and abort these steps.
      4. +
      5. If the origin is not the same as the service worker's origin, then: +
          +
        1. Resolve promise with null.
        2. +
        3. Abort these steps.
        4. +
        +
      6. +
      7. Let client be the result of running Capture Window Client algorithm, or its equivalent, with browsingContext as the argument.
      8. +
      9. Resolve promise with client.
      10. +
      +
    6. +
    +
  12. +
  13. Return promise.
  14. +
+
+
+
+
4.3

Clients

+ + +
[Exposed=ServiceWorker]
+interface Clients {
+  // The objects returned will be new instances every time
+  [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
+  [NewObject] Promise<WindowClient?> openWindow(USVString url);
+  [NewObject] Promise<void> claim();
+};
+
+dictionary ClientQueryOptions {
+  boolean includeUncontrolled = false;
+  ClientType type = "window";
+};
+
+enum ClientType {
+  "window",
+  "worker",
+  "sharedworker",
+  "all"
+};
+
+

The Clients interface represents a container for a list of Client objects.

+
4.3.1

matchAll(options)

+ +

The matchAll(options) method must run these steps or their equivalent:

+
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let clients be an empty array.
    2. +
    3. If the optional argument options is omitted, then: +
        +
      1. For each service worker client client whose active worker is the associated service worker, in the most recently focused order for window clients: +
          +
        1. If client is a window client, then: +
            +
          1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
          2. +
          3. Add windowClient to clients.
          4. +
          +
        2. +
        +
      2. +
      3. Resolve promise with clients.
      4. +
      +
    4. +
    5. Else: +
        +
      1. Let targetClients be an empty array.
      2. +
      3. For each service worker client client whose origin is the same as the associated service worker's origin: +
          +
        1. If options.includeUncontrolled is false, then: +
            +
          1. If client's active worker is the associated service worker, add client to targetClients.
          2. +
          +
        2. +
        3. Else: +
            +
          1. Add client to targetClients.
          2. +
          +
        4. +
        +
      4. +
      5. Let matchedClients be an empty array.
      6. +
      7. For each service worker client client in targetClients, in the most recently focused order for window clients: +
          +
        1. If options.type is "window", and client is a window client, then: +
            +
          1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
          2. +
          3. Add windowClient to matchedClients.
          4. +
          +
        2. +
        3. Else if options.type is "worker" and client is a dedicated worker client, add a Client object that represents client to matchedClients.
        4. +
        5. Else if options.type is "sharedworker" and client is a shared worker client, add a Client object that represents client to matchedClients.
        6. +
        7. Else if options.type is "all", then: +
            +
          1. If client is a window client, then: +
              +
            1. Let windowClient be the result of running Capture Window Client algorithm, or its equivalent, with client's responsible browsing context as the argument.
            2. +
            3. Add windowClient to matchedClients.
            4. +
            +
          2. +
          3. Else, add a Client object that represents client to matchedClients.
          4. +
          +
        +
      8. +
      9. Resolve promise with matchedClients.
      10. +
      +
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+
4.3.2

openWindow(url)

+ +

The openWindow(url) method must run these steps or their equivalent:

+
+
    +
  1. Let url be the result of parsing url with entry settings object's API base URL.
  2. +
  3. If url is failure, return a promise rejected with a TypeError.
  4. +
  5. If url is about:blank, return a promise rejected with a TypeError.
  6. +
  7. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception.
  8. +
  9. Let promise be a new promise.
  10. +
  11. Run these steps in parallel: +
      +
    1. Let newContext be a new top level browsing context.
    2. +
    3. Navigate newContext to url, with exceptions enabled and replacement enabled.
    4. +
    5. If the navigation throws an exception, reject promise with that exception and abort these steps.
    6. +
    7. If the origin is not the same as the service worker's origin, then: +
        +
      1. Resolve promise with null.
      2. +
      3. Abort these steps.
      4. +
      +
    8. +
    9. Let client be the result of running Capture Window Client algorithm, or its equivalent, with newContext as the argument.
    10. +
    11. Resolve promise with client.
    12. +
    +
  12. +
  13. Return promise.
  14. +
+
+
+ +
4.3.3

claim()

+ +

The claim() method must run these steps or their equivalent:

+
+
    +
  1. If the service worker is not an active worker, return a promise rejected with an "InvalidStateError" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run the following substeps in parallel: +
      +
    1. For each service worker client client whose origin is the same as the service worker's origin: +
        +
      1. Let registration be the result of running Match Service Worker Registration algorithm passing client's creation url as the argument.
      2. +
      3. If registration is not the service worker's containing service worker registration, continue to the next iteration of the loop.
      4. +
      5. If client's active worker is not the service worker, then: +
          +
        1. Invoke Handle Service Worker Client Unload with client as the argument.
        2. +
        3. Set client's active worker to service worker.
        4. +
        5. Invoke Notify Controller Change algorithm with client as the argument.
        6. +
        +
      6. +
      +
    2. +
    3. Resolve promise with undefined.
    4. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+
+ + + +
4.4

ExtendableEvent

+ + +
[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
+interface ExtendableEvent : Event {
+  void waitUntil(Promise<any> f);
+};
+
+dictionary ExtendableEventInit : EventInit {
+  // Defined for the forward compatibility across the derived events
+};
+
+ +

An ExtendableEvent object has an associated extend lifetime promises (an array of promises). It is initially set to null.

+ +

Service workers have two lifecycle events, install and activate. Service workers use the ExtendableEvent interface for activate event and install event.

+ +

Service worker extensions that define event handlers may also use or extend the ExtendableEvent interface.

+ +
4.4.1

event.waitUntil(f)

+ + +

waitUntil(f) method extends the lifetime of the event.

+ +

waitUntil(f) method must run these steps or their equivalent:

+
+
    +
  1. If the active function is not the callback of the event handler whose type is the context object's type value, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. Add f to extend lifetime promises.
  4. +
+
+ +

In the task task in which the steps of waitUntil(f) is running, the user agent must run these steps or their equivalent:

+
+
    +
  1. Let extendLifetimePromises be an empty array.
  2. +
  3. For each event listener invoked: +
      +
    1. Let eventObject be the first argument passed to this event listener.
    2. +
    3. Append eventObject's extend lifetime promises to extendLifetimePromises.
    4. +
    +
  4. +
  5. Do not terminate the service worker whose responsible event loop is running task until waiting for all of extendLifetimePromises settles.
  6. +
+
+

However, the user agent may impose a time limit to this lifetime extension.

+ +

Service workers and extensions that define event handlers may define their own behaviours, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

+ +

Service workers define the following behaviours for install event and activate event: +

+

+
+
+ +
4.5

FetchEvent

+ + +
[Constructor(DOMString type, optional FetchEventInit eventInitDict), Exposed=ServiceWorker]
+interface FetchEvent : ExtendableEvent {
+  [SameObject] readonly attribute Request request;
+  [SameObject] readonly attribute Client client;
+  readonly attribute boolean isReload;
+
+  void respondWith((Response or Promise<Response>) r);
+};
+
+dictionary FetchEventInit : ExtendableEventInit {
+  Request request;
+  Client client;
+  boolean isReload = false;
+};
+
+

Service workers have an essential functional event fetch. For fetch event, service workers use the FetchEvent interface which extends the ExtendableEvent interface.

+ +

Each event using FetchEvent interface has the following associated flag that is initially unset: +

    +
  • wait to respond flag
  • +
  • respond-with entered flag
  • +
  • respond-with error flag
  • +
+

+ +
4.5.1

event.request

+ + +

request attribute must return the value it was initialized to.

+
+ +
4.5.2

event.client

+ + +

client attribute must return the value it was initialized to.

+
+ +
4.5.3

event.isReload

+ + +

isReload attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

+

Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

+
+ +
4.5.4

event.respondWith(r)

+ + +

When event.respondWith(r) method is invoked, the argument, r, must resolve with a Response, else a network error is returned to Fetch. If the request is a top-level navigation and the return value is a Response whose type attribute is "opaque" (i.e., an opaque response body), a network error is returned to Fetch. The final URL of all successful (non network-error) responses is the requested URL. Renderer-side security checks about tainting for cross-origin content are tied to the transparency (or opacity) of the Response body, not URLs.

+ +

respondWith(r) method must run these steps or their equivalent:

+
+
    +
  1. If the active function is not the callback of the event handler whose type is fetch, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. If the respond-with entered flag is set, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  4. +
  5. Set the stop propagation flag and stop immediate propagation flag.
  6. +
  7. Set the respond-with entered flag.
  8. +
  9. Set the wait to respond flag.
  10. +
  11. Let responsePromise be null.
  12. +
  13. If r is a Response object, then: +
      +
    1. Set responsePromise to a promise resolved with r.
    2. +
    +
  14. +
  15. Else: +
      +
    1. Set responsePromise to r.
    2. +
    +
  16. +
  17. Run the following substeps in parallel: +
      +
    1. Wait until responsePromise settles.
    2. +
    3. If responsePromise rejected, then: +
        +
      1. Set the respond-with error flag.
      2. +
      +
    4. +
    5. If responsePromise resolved with response, then: +
        +
      1. If response is a Response object, then: +
          +
        1. Let request be the context object's request attribute value.
        2. +
        3. If response.type is "opaque", and request's associated request is a client request, set the respond-with error flag.
        4. +
        5. If response's body is non-null, then: +
            +
          1. If response's used flag is set, set the respond-with error flag.
          2. +
          3. Set response's used flag.
          4. +
          +
        6. +
        +
      2. +
      3. Else: +
          +
        1. Set the respond-with error flag.
        2. +
        +

        If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 22.1.)

        +
      4. +
      +
    6. +
    7. Unset the wait to respond flag.
    8. +
    +
  18. +
+
+
+
+ +
4.6

ExtendableMessageEvent

+ + +
[Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
+interface ExtendableMessageEvent : ExtendableEvent {
+  readonly attribute any data;
+  readonly attribute DOMString origin;
+  readonly attribute DOMString lastEventId;
+  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
+  [SameObject] readonly attribute MessagePort[]? ports;
+};
+
+dictionary ExtendableMessageEventInit : ExtendableEventInit {
+  any data;
+  DOMString origin;
+  DOMString lastEventId;
+  (Client or ServiceWorker or MessagePort)? source;
+  sequence<MessagePort> ports;
+};
+
+

Service workers define the extendable message event that extends the message event defined in HTML to allow extending the lifetime of the event. For the message event, service workers use the ExtendableMessageEvent interface which extends the ExtendableEvent interface.

+ +
4.6.1

event.data

+ +

The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

+
+ +
4.6.2

event.origin

+ +

The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker client that sent the message.

+
+ +
4.6.3

event.lastEventId

+ +

The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

+
+ +
4.6.4

event.source

+ +

The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the Client object from which the message is sent.

+ +

When navigator.connect() API extends the communication model between cross origin service workers, this attribute may also represent ServicePort object from which the message is sent.

+
+ +
4.6.5

event.ports

+ +

The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

+
+
+ +
4.7

Events

+ + +

The following events are dispatched on ServiceWorkerGlobalScope object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
installExtendableEvent[Lifecycle event] The service worker's containing service worker registration's installing worker changes. (See step 11.2 of the Install algorithm.)
activateExtendableEvent[Lifecycle event] The service worker's containing service worker registration's active worker changes. (See step 15.2 of the Activate algorithm.)
fetchFetchEvent[Functional event] Fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the Service Woker returns a response to Fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method. (A custom Response object can be another option.)
messageExtendableMessageEventWhen it receives a message.
+
+
+ +
5

Caches

+ +

To allow authors to fully manage their content caches for offline use, the Window and the WorkerGlobalScope provide the asynchronous caching methods that open and manipulate Cache objects. An origin can have multiple, named Cache objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser's HTTP cache.

+ +
5.1

Constructs

+ + +

A fetching record is a Record {[[key]], [[value]]} where [[key]] is a Request and [[value]] is a Response.

+

A fetching record has an associated incumbent record (a fetching record). It is initially set to null.

+

A request to response map is a List of fetching records.

+ +

A name to cache map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a name of the Cache object and [[value]] is a Cache object.

+ +

Each origin has an associated name to cache map.

+
+ +
5.2

Understanding Cache Lifetimes

+ + +

The Cache instances are not part of the browser's HTTP cache. The Cache objects are exactly what authors have to manage themselves. The Cache objects do not get updated unless authors explicitly request them to be. The Cache objects do not expire unless authors delete the entries. The Cache objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

+
+ +
5.3

self.caches

+ +
partial interface Window {
+  [SameObject] readonly attribute CacheStorage caches;
+};
+
+partial interface WorkerGlobalScope {
+  [SameObject] readonly attribute CacheStorage caches;
+};
+
+
5.3.1

caches

+ + +

caches attribute must return a CacheStorage object that represents the name to cache map of the context object's environment settings object's origin.

+
+
+ +
5.4

Cache

+ +
[Exposed=(Window,Worker)]
+interface Cache {
+  [NewObject] Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
+  [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+  [NewObject] Promise<void> add(RequestInfo request);
+  [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
+  [NewObject] Promise<void> put(RequestInfo request, Response response);
+  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
+  [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
+};
+
+dictionary CacheQueryOptions {
+  boolean ignoreSearch = false;
+  boolean ignoreMethod = false;
+  boolean ignoreVary = false;
+  DOMString cacheName;
+};
+
+dictionary CacheBatchOperation {
+  DOMString type;
+  Request request;
+  Response response;
+  CacheQueryOptions options;
+};
+
+

A Cache object represents a request to response map. Multiple separate objects implementing the Cache interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

+ +

Cache objects are always enumerable via self.caches in insertion order (per ECMAScript 6 Map objects.)

+ +
5.4.1

match(request, options)

+ + +

match(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let p be the result of running the algorithm specified in matchAll(request, options) method with request and options as the arguments.
    2. +
    3. Wait until p settles.
    4. +
    5. If p rejects with an exception, then: +
        +
      1. Reject promise with that exception.
      2. +
      +
    6. +
    7. Else if p resolves with an array, responseArray, then: +
        +
      1. If responseArray is an empty array, then: +
          +
        1. Resolve promise with undefined.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Resolve promise with the first element of responseArray.
        2. +
        +
      4. +
      +
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
5.4.2

matchAll(request, options)

+ + +

matchAll(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let responseArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add a copy of entry.[[value]] to responseArray.
        2. +
        +
      2. +
      3. Resolve promise with responseArray.
      4. +
      5. Abort these steps.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a Request object, then: +
          +
        1. Set r to request's request.
        2. +
        3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
        4. +
        +
      4. +
      5. Else if request is a string, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let entries be the result of running Query Cache algorithm passing a Request object associated with r and options as the arguments.
      10. +
      11. For each entry of entries: +
          +
        1. Let response be null.
        2. +
        3. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, set response to a copy of incumbentRecord.[[value]].
        4. +
        5. Else, set response to a copy of entry[1].
        6. +
        7. If r's method is `HEAD` and options.ignoreMethod is false, set response's body to null.
        8. +
        9. Add response to responseArray.
        10. +
        +
      12. +
      13. Resolve promise with responseArray.
      14. +
      +
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
5.4.3

add(request)

+ + +

add(request) method must run these steps or their equivalent:

+ +
+
    +
  1. Let requests be an array containing only request.
  2. +
  3. Set responseArrayPromise to the result of running the algorithm specified in addAll(requests) passing requests as the argument.
  4. +
  5. Return the result of transforming responseArrayPromise with a fulfillment handler that returns undefined.
  6. +
+
+
+ +
5.4.4

addAll(requests)

+ + +

addAll(requests) method must run these steps or their equivalent:

+ +
+
    +
  1. Let responsePromiseArray be an empty array.
  2. +
  3. Let requestArray be an empty array.
  4. +
  5. For each request whose type is Request in requests: +
      +
    1. Let r be request's request.
    2. +
    3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
    4. +
    +
  6. +
  7. For each request in requests: +
      +
    1. Let r be the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    3. If r's url's scheme is not one of "http" and "https", then: +
        +
      1. Terminate all the ongoing fetches initiated by requests with reason fatal.
      2. +
      3. Break the loop.
      4. +
      +
    4. +
    5. Set r's url's fragment to null.
    6. +
    7. Set r's context to "fetch".
    8. +
    9. Add a Request object associated with r to requestArray.
    10. +
    11. Let responsePromise be a new promise.
    12. +
    13. Run the following in parallel: +
        +
      • Fetch r.
      • +
      • To process response for response, run these substeps: +
          +
        1. If response's type is error, reject responsePromise with a TypeError.
        2. +
        3. Else if response's header list contains a header named `Vary`, then: +
            +
          1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
          2. +
          3. Let matchAsterisk be false.
          4. +
          5. For each f in varyHeaders: +
              +
            1. If f matches "*", set matchAsterisk to true and break the loop.
            2. +
            +
          6. +
          7. If matchAsterisk is true, reject responsePromise with a TypeError.
          8. +
          9. Else, resolve responsePromise with a new Response object associated with response.
          10. +
          +
        4. +
        5. Else, resolve responsePromise with a new Response object associated with response.
        6. +
        +

        This step ensures that the promise for this fetch resolves as soon as the response's headers become available.

        +
      • +
      • To process response body for response, do nothing.
      • +
      • To process response end-of-file for response, do nothing.
      • +
      +
    14. +
    15. Add responsePromise to responsePromiseArray.
    16. +
    +
  8. +
  9. Let p be waiting for all of responsePromiseArray.
  10. +
  11. Return the result of transforming p with a fulfillment handler that, when called with argument responseArray, performs the following substeps in parallel: +
      +
    1. Let operations be an empty array.
    2. +
    3. For each response in responseArray with the index index: +
        +
      1. If response's body is non-null, then: +
          +
        1. If response's used flag is set, throw a TypeError.
        2. +
        3. Set response's used flag.
        4. +
        +
      2. +
      3. Let o be an empty object representing a CacheBatchOperation dictionary.
      4. +
      5. Set the type dictionary member of o to "put".
      6. +
      7. Set the request dictionary member of o to requestArray[index].
      8. +
      9. Set the response dictionary member of o to response.
      10. +
      11. Add o to operations.
      12. +
      +
    4. +
    5. Let resultPromise to the result of running Batch Cache Operations algorithm passing operations as the argument.
    6. +
    7. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
        +
      1. Let responseBodyPromiseArray be an empty array.
      2. +
      3. For each response in responses: +
          +
        1. Let responseBodyPromise be a new promise.
        2. +
        3. Run the following substeps in parallel: +
            +
          1. Wait for either end-of-file to have been pushed to response's associated response r's body or for r to have a termination reason.
          2. +
          3. If r had a termination reason, then: +
              +
            1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
                +
              1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
              2. +
              +
            2. +
            3. Else: +
                +
              1. Delete fetchingRecord from request to response map.
              2. +
              +
            4. +
            5. Reject responseBodyPromise with a TypeError.
            6. +
            +
          4. +
          5. Else: +
              +
            1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
            2. +
            3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
            4. +
            5. For each invalidRecord in invalidRecords: +
                +
              1. If invalidRecord is not fetchingRecord, delete it from request to response map.
              2. +
              +
            6. +
            7. Resolve responseBodyPromise with response.
            8. +
            +
          6. +
          +
        4. +
        5. Add responseBodyPromise to responseBodyPromiseArray.
        6. +
        +
      4. +
      5. Let q be waiting for all of responseBodyPromiseArray.
      6. +
      7. Return the result of transforming q with a fulfillment handler that returns undefined.
      8. +
      +
    8. +
    +
  12. +
+
+
+ +
5.4.5

put(request, response)

+ + +

put(request, response) method must run these steps or their equivalent:

+ +
+
    +
  1. Let r be null.
  2. +
  3. If request is a Request object, then: +
      +
    1. Set r to request's request.
    2. +
    3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
    4. +
    +
  4. +
  5. Else if request is a string, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    3. If r's url's scheme is not one of "http" and "https", return a promise rejected with a TypeError.
    4. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. If response's associated response's header list contains a header named `Vary`, then: +
      +
    1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
    2. +
    3. For each f in varyHeaders: +
        +
      1. If f matches "*", return a promise rejected with a TypeError.
      2. +
      +
    4. +
    +
  10. +
  11. If response's body is non-null, then: +
      +
    1. If response's used flag is set, return a promise rejected with a TypeError.
    2. +
    3. Set response's used flag.
    4. +
    +
  12. +
  13. Let operations be an empty array.
  14. +
  15. Let o be an empty object representing a CacheBatchOperation dictionary.
  16. +
  17. Set the type dictionary member of o to "put".
  18. +
  19. Set the request dictionary member of o to a Request object associated with r.
  20. +
  21. Set the response dictionary member of o to response.
  22. +
  23. Add o to operations.
  24. +
  25. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
  26. +
  27. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
      +
    1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r's body or for r to have a termination reason.
    2. +
    3. If r had a termination reason, then: +
        +
      1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
          +
        1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Delete fetchingRecord from request to response map.
        2. +
        +
      4. +
      5. Throw a TypeError.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
      2. +
      3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
      4. +
      5. For each invalidRecord in invalidRecords: +
          +
        1. If invalidRecord is not fetchingRecord, delete it from request to response map.
        2. +
        +
      6. +
      7. Return undefined.
      8. +
      +
    6. +
    +
  28. +
+
+
+ +
5.4.6

delete(request, options)

+ + +

delete(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let r be null.
  2. +
  3. If request is a Request object, then: +
      +
    1. Set r to request's request.
    2. +
    3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, return a promise resolved with false.
    4. +
    +
  4. +
  5. Else if request is a string, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. Let operations be an empty array.
  10. +
  11. Let o be an empty object representing a CacheBatchOperation dictionary.
  12. +
  13. Set the type dictionary member of o to "delete".
  14. +
  15. Set the request dictionary member of o to a Request object associated with r.
  16. +
  17. Set the options dictionary member of o to options.
  18. +
  19. Add o to operations.
  20. +
  21. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
  22. +
  23. Return the result of transforming resultPromise with a fulfillment handler, when called with argument responseArray, performs the following substeps in parallel: +
      +
    1. If responseArray is not null, return true.
    2. +
    3. Else, return false.
    4. +
    +
  24. +
+
+
+ +
5.4.7

keys(request, options)

+ + +

keys(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run these steps in parallel: +
      +
    1. Let resultArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add entry.[[key]] to resultArray.
        2. +
        +
      2. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a Request object, then: +
          +
        1. Set r to request's request.
        2. +
        3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
        4. +
        +
      4. +
      5. Else if request is a string, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let requestResponseArray be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments.
      10. +
      11. For each requestResponse in requestResponseArray: +
          +
        1. Add requestResponse[0] to resultArray.
        2. +
        +
      12. +
      +
    6. +
    7. Resolve promise with resultArray.
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+
+ +
5.5

CacheStorage

+ + +
[Exposed=(Window,Worker)]
+interface CacheStorage {
+  [NewObject] Promise<Response> match(RequestInfo request, optional CacheQueryOptions options);
+  [NewObject] Promise<boolean> has(DOMString cacheName);
+  [NewObject] Promise<Cache> open(DOMString cacheName);
+  [NewObject] Promise<boolean> delete(DOMString cacheName);
+  [NewObject] Promise<sequence<DOMString>> keys();
+};
+ + +

CacheStorage interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

+ +

A CacheStorage object represents a name to cache map. Multiple separate objects implementing the CacheStorage interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

+ +
5.5.1

match(request, options)

+ + +

match(request, options) method must run these steps or their equivalent:

+ +
+
    +
  1. If the result of running is settings object a secure context with the incumbent settings object is Not Secure, return a new promise rejected with a "SecurityError" exception.
  2. +
  3. Let cacheName be null.
  4. +
  5. If the optional argument options is not omitted, then: +
      +
    1. Set cacheName to options.cacheName.
    2. +
    +
  6. +
  7. If cacheName is not null, then: +
      +
    1. Return a new promise p and run the following substeps in parallel: +
        +
      1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. If cacheName matches entry.[[key]], then: +
            +
          1. Resolve p with the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).)
          2. +
          3. Abort these steps.
          4. +
          +
        2. +
        +
      2. +
      3. Reject p with a "NotFoundError" exception.
      4. +
      +
    2. +
    +
  8. +
  9. Else: +
      +
    1. Let p be a new promise resolved with undefined.
    2. +
    3. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. Set p to the result of transforming itself with a fulfillment handler that, when called with argument v, performs the following substeps in parallel: +
          +
        1. If v is not undefined, return v.
        2. +
        3. Return the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).)
        4. +
        +
      2. +
      +
    4. +
    5. Return p.
    6. +
    +
  10. +
+
+
+ +
5.5.2

has(cacheName)

+ + +

has(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. If the result of running is settings object a secure context with the incumbent settings object is Not Secure, return a new promise rejected with a "SecurityError" exception.
  2. +
  3. Return a new promise p resolved with the result of running the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.[[key]], then: +
          +
        1. Return true.
        2. +
        +
      2. +
      +
    2. +
    3. Return false.
    4. +
    +
  4. +
+
+
+ +
5.5.3

open(cacheName)

+ + +

open(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. If the result of running is settings object a secure context with the incumbent settings object is Not Secure, return a new promise rejected with a "SecurityError" exception.
  2. +
  3. Let p be a new promise.
  4. +
  5. Run the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.[[key]], then: +
          +
        1. Resolve p with a new Cache object which is a copy of entry.[[value]].
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      +
    2. +
    3. Let cache be a new Cache object.
    4. +
    5. Set a newly-created Record {[[key]]: cacheName, [[value]]: cache} to name to cache map. If this cache write operation failed due to exceeding the granted quota limit, reject p with a "QuotaExceededError" exception and abort these steps.
    6. +
    7. Resolve p with cache.
    8. +
    +
  6. +
  7. Return p.
  8. +
+
+
+ +
5.5.4

delete(cacheName)

+ + +

delete(cacheName) method must run these steps or their equivalent:

+ +
+
    +
  1. If the result of running is settings object a secure context with the incumbent settings object is Not Secure, return a new promise rejected with a "SecurityError" exception.
  2. +
  3. Let p be the result of running the algorithm specified in has(cacheName) method with cacheName as the argument.
  4. +
  5. Return the result of transforming p with a fulfillment handler that, when called with argument cacheExists, performs the following substeps in parallel: +
      +
    1. If cacheExists is true, then: +
        +
      1. Delete a Record {[[key]], [[value]]} entry of its name to cache map where cacheName matches entry.[[key]].
      2. +
      3. Return true.
      4. +
      5. Abort these steps.
      6. +
      +
    2. +
    3. Else: +
        +
      1. Return false.
      2. +
      +
    4. +
    +
  6. +
+
+
+ +
5.5.5

keys()

+ + +

keys() method must run these steps or their equivalent:

+ +

The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

+ +
+
    +
  1. If the result of running is settings object a secure context with the incumbent settings object is Not Secure, return a new promise rejected with a "SecurityError" exception.
  2. +
  3. Let resultArray be an empty array.
  4. +
  5. Return a new promise p resolved with the result of running the following substeps: +
      +
    1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. Add entry.[[key]] to resultArray.
      2. +
      +
    2. +
    3. Return resultArray.
    4. +
    +
  6. +
+
+
+
+
+ +
6

Security Considerations

+ + +

Service workers should be implemented to be HTTPS-only. The reasons for SSL-only support include:

+ + +

The section will be updated.

+ +
6.1

Origin Relativity

+ + +

One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

+ +
6.1.1

importScripts(urls)

+ + +

The importScripts(urls) method is defined on the WorkerGlobalScope interface. The following algorithm steps monkey patch the method to embrace the service worker environment. The corresponding change request has been filed in HTML: Issue 28737.

+ +

When the importScripts(urls) method is called on a ServiceWorkerGlobalScope object, the following steps, or their equivalent, must be run replacing the step 5 of importScripts(urls):

+ +
+
    +
  1. Let serviceWorker be the incumbent settings object's global object's service worker.
  2. +
  3. If serviceWorker's imported scripts updated flag is unset, then: +
      +
    1. Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set.
    2. +
    +
  4. +
  5. Else: +
      +
    1. For each absolute URL url in the resulting absolute URLs: +
        +
      1. If there exists a corresponding Record record for url in serviceWorker's script resource map, set the script resource used in the step 6 to record.[[value]].
      2. +
      3. Else, throw a "NetworkError" exception.
      4. +
      +
    2. +
    +
  6. +
+
+ +

The following steps, or their equivalent, must be run at the end (as a part) of the step 6.1 of importScripts(urls):

+ +
+
    +
  1. If the script resource has been obtained through running fetch, then: +
      +
    1. If there exists a corresponding Record record for the resulting absolute URL url in serviceWorker's script resource map, set record.[[value]] to the fetched script resource.
    2. +
    3. Else, set a newly-created Record {[[key]]: url, [[value]]: the fetched script resource} to serviceWorker's script resource map.
    4. +
    +
  2. +
+
+ +

The following step, or its equivalent, must be run as the step 7 of importScripts(urls):

+ +
+
    +
  1. Set serviceWorker's imported scripts updated flag if all the attempts have succeeded without any error.
  2. +
+
+
+
+ +
6.2

Cross-Origin Resources and CORS

+ + +

Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to XHR many sorts of off-origin resources when appropriate CORS headers are set.

+

ServiceWorkers enable this by allowing Caches to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the Cache as Response objects with the type attribute set to "basic", the objects stored are Response objects with the type attribute set to "opaque". Responses typed "opaque" provide a much less expressive API than Responses typed "basic"; the bodies and headers cannot be read or set, nor many of the other aspects of their content inspected. They can be passed to event.respondWith(r) method in the same manner as the Responses typed "basic", but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Caches to store them allows applications to avoid re-architecting in most cases.

+

The section will be updated.

+
+
+ +
7

Storage Considerations

+ + +

Service workers should take a dependency on Quota Management API that extends the ServiceWorkerGlobalScope with the event listeners onbeforeevicted and onevicted to detect a storage pressure and give pre-eviction information to the application.

+

The cache write operations in service workers when failed due to exceeding the granted quota limit should throw "QuotaExceededError" exception.

+
+ +
8

Extensibility

+ + +

Service workers are extensible from other specifications.

+ +
8.1

Define API bound to Service Worker Registration

+ +

Specifications may define an API tied to a service worker registration by using partial interface definition to the ServiceWorkerRegistration interface where it may define the specification specific attributes and methods:

+ +
partial interface ServiceWorkerRegistration {
+  // e.g. define an API namespace
+  readonly attribute APISpaceType APISpace;
+  // e.g. define a method
+  Promise<T> methodName(list of arguments);
+};
+
+
+ +
8.2

Define Functional Event

+ +

Specifications may define a functional event by extending ExtendableEvent interface:

+ +
// e.g. define FunctionalEvent interface
+interface FunctionalEvent : ExtendableEvent {
+  // add a functional event's own attributes and methods
+};
+
+
+ +
8.3

Define Event Handler

+ +

Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the ServiceWorkerGlobalScope interface:

+ +
partial interface ServiceWorkerGlobalScope {
+  attribute EventHandler onfunctionalevent;
+};
+
+ +
8.4

Request Functional Event Dispatch

+ +

To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

+ +

Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a ServiceWorkerGlobalScope object) at which it may fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm.

+ +

See an example hook defined in Notifications API.

+
+
+ +
9

Appendix A: Algorithms

+ + +

The following definitions are the user agent's internal data structures used throughout the specification.

+ +

A scope to registration map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a scope url and [[value]] is a service worker registration.

+ +

An algorithm thread queue is a thread safe queue used to synchronize the set of concurrent entries of algorithm steps. The queue contains timestamps (with the assumptions), gained by algorithms, as its elements. The queue should satisfy the general properties of FIFO queue.

+ +

A registration queue is an algorithm thread queue for synchronizing the set of concurrent registration requests. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +

An installation queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +

An installation result handle queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +

An activation queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

+ +
9.1

Register

+ + +
+
+
Input
+
client, a service worker client
+
scriptURL, an absolute URL
+
scopeURL, an absolute URL
+
Output
+
promise, a promise
+
+
    +
  1. If the result of running Is origin potentially trustworthy with the origin of scriptURL as the argument is Not Trusted, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  2. +
  3. If the origin of scriptURL is not client's origin, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  4. +
  5. If the origin of scopeURL is not client's origin, then: +
      +
    1. Return a promise rejected with a "SecurityError" exception.
    2. +
    +
  6. +
  7. Run the following substeps atomically: +
      +
    1. Let registration be the result of running the Get Registration algorithm passing scopeURL as the argument.
    2. + +
    3. If registration is not null, then: +
        +
      1. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
      2. +
      3. If newestWorker is not null, scriptURL is equal to newestWorker's script url, and scriptURL is equal to registration's registering script url, then: +
          +
        1. If newestWorker is an active worker, then: +
            +
          1. If registration's uninstalling flag is set, unset it.
          2. +
          3. Return a promise resolved with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
          4. +
          +
        2. +
        +
      4. +
      +
    4. +
    5. Else: +
        +
      1. Set registration to the result of running Set Registration algorithm passing scopeURL as its argument.
      2. +
      +
    6. +
    7. Set registration's registering script url to scriptURL.
    8. +
    9. Return the result of running the Update algorithm, or its equivalent, passing client and registration as the argument.
    10. +
    +
  8. +
+
+
+ +
9.2

Update

+ + +

The algorithm uses registration queue to synchronize the set of multiple registration requests. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

+ + +
+
+
Input
+
client, a service worker client
+
registration, a service worker registration
+
Output
+
promise, a promise
+
+
    +
  1. Let p be a new promise.
  2. +
  3. Generate a timestamp and let timeStamp be the result value.
  4. +
  5. Push timeStamp to registration queue, installation queue, and installation result handle queue.
  6. +
  7. Run the following substeps in parallel: +
      +
    1. CheckPriority: If the value of the top element of registration queue is not timeStamp, then: +
        +
      1. Wait until the top element of registration queue is popped.
      2. +
      3. Jump to the step labeled CheckPriority.
      4. +
      +

      Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

      +
    2. +
    3. If registration's installing worker is not null, then: +
        +
      1. Terminate registration's installing worker.
      2. +
      3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      4. +
      5. Set registration's installing worker to null.
      6. +
      7. The user agent may abort in-flight requests triggered by registration's installing worker.
      8. +
      +
    4. +
    5. Let r be the associated request of the result of invoking the initial value of Request as constructor with registration's serialized registering script url. If this throws an exception, then: +
        +
      1. Reject p with the exception.
      2. +
      3. Pop the top element from registration queue, installation queue and installation result handle queue.
      4. +
      5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Abort these steps.
      8. +
      +
    6. +
    7. Set r's context to serviceworker.
    8. +
    9. Set r's client to client.
    10. +
    11. Append `Service-Worker`/`script` to r's header list.
    12. +
    13. Set r's skip service worker flag, r's synchronous flag, and r's redirect mode to "manual".
    14. +
    15. Let response be the result of running fetch using r, forcing a network fetch if cached entry is greater than 1 day old.
    16. +
    17. If response is a network error or response's status is not in the range 200 to 299, then: +
        +
      1. Reject p with a TypeError.
      2. +
      3. Pop the top element from registration queue, installation queue and installation result handle queue.
      4. +
      5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Abort these steps.
      8. +
      +
    18. +
    19. Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
        +
      1. Reject p with a "SecurityError" exception.
      2. +
      3. Pop the top element from registration queue, installation queue and installation result handle queue.
      4. +
      5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Abort these steps.
      8. +
      +
    20. +
    21. Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response's header list.
    22. +
    23. If serviceWorkerAllowed is failure, then: +
        +
      1. Reject p with a TypeError.
      2. +
      3. Pop the top element from registration queue, installation queue and installation result handle queue.
      4. +
      5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Abort these steps.
      8. +
      +
    24. +
    25. Let scopeURL be registration's scope url.
    26. +
    27. Let maxScopeString be null.
    28. +
    29. If serviceWorkerAllowed is null, then: +
        +
      1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script's file name, in registration's registering script url's path (including empty strings), separated from each other by "/".
      2. +
      +
    30. +
    31. Else: +
        +
      1. Let maxScope be the result of parsing serviceWorkerAllowed with registration's registering script url.
      2. +
      3. Set maxScopeString to "/" concatenated with the strings in maxScope's path (including empty strings), separated from each other by "/".
      4. +
      +
    32. +
    33. Let scopeString be "/" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/".
    34. +
    35. If scopeString starts with maxScopeString, do nothing.
    36. +
    37. Else: +
        +
      1. Reject p with a "SecurityError" exception.
      2. +
      3. Pop the top element from registration queue, installation queue and installation result handle queue.
      4. +
      5. If the result of running Get Newest Worker algorithm passing registration as the argument is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Abort these steps.
      8. +
      +
    38. +
    39. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
    40. +
    41. If newestWorker is not null, and newestWorker's script url is equal to registration's registering script url and response is a byte-for-byte match with the script resource of newestWorker, then: +
        +
      1. Resolve p with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
      2. +
      3. Abort these steps.
      4. +
      +
    42. +
    43. Else: +
        +
      1. Let worker be a new service worker.
      2. +
      3. Set worker's script url to registration's registering script url. (worker's script resource is the fetched response.) Generate a new UUID and set worker's id to the value.
      4. +
      5. Invoke Run Service Worker algorithm with worker as the arguement.
      6. +
      7. If an uncaught runtime script error occurs during the above step, then: +
          +
        1. Reject p with the error.
        2. +
        3. Pop the top element from registration queue, installation queue and installation result handle queue.
        4. +
        5. If the result of running Get Newest Worker algorithm passing registration as its argument is null, then: +
            +
          1. Invoke Clear Registration algorithm passing registration as its argument.
          2. +
          +
        6. +
        7. Abort these steps.
        8. +
        +
      8. +
      +
    44. +
    45. Pop the top element from registration queue.
    46. +
    47. Invoke Install algorithm, or its equivalent, with client, registration, worker, p, and timeStamp as its arguments.
    48. +
    +
  8. +
  9. Return p.
  10. +
+
+
+ +
9.3

Soft Update

+ + +

The user agent may call this as often as it likes to check for updates.

+ +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Let client be null.
  2. +
  3. If registration's uninstalling flag is set, abort these steps.
  4. +
  5. If registration's installing worker is not null, abort these steps.
  6. +
  7. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
  8. +
  9. If newestWorker is null, abort these steps.
  10. +
  11. Set registration's registering script url to newestWorker's script url.
  12. +
  13. Invoke Update algorithm, or its equivalent, with client, registration as its argument.
  14. +
+
+
+ +
9.4

Install

+ + +

The algorithm uses installation queue to synchronize the set of multiple installation jobs. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

+ +
+
+
Input
+
client, a service worker client
+
registration, a service worker registration
+
worker, a service worker
+
registrationPromise, a promise
+
timeStamp, a timestamp
+
Output
+
none
+
+
    +
  1. Let installFailed be false.
  2. +
  3. CheckPriority: If the value of the top element of installation queue is not timeStamp, then: +
      +
    1. Wait until the top element of installation queue is popped.
    2. +
    3. Jump to the step labeled CheckPriority.
    4. +
    +

    Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

    +
  4. +
  5. If registration's installing worker is not null, then: +
      +
    1. Terminate registration's installing worker.
    2. +
    3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    4. +
    5. The user agent may abort any in-flight requests triggered by registration's installing worker.
    6. +
    +
  6. +
  7. Set registration's installing worker to worker.
  8. +
  9. Run the Update State algorithm passing registration's installing worker and installing as the arguments.
  10. +
  11. Assert: registrationPromise is not null.
  12. +
  13. Resolve registrationPromise with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
  14. +
  15. Queue a task to fire a simple event named updatefound at all the ServiceWorkerRegistration objects that represent registration for all the service worker clients whose creation url matches registration's scope url.
  16. +
  17. Let installingWorker be registration's installing worker.
  18. +
  19. Invoke Run Service Worker algorithm with installingWorker as the arguement.
  20. +
  21. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the ExtendableEvent interface, with the event type install, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Dispatch e at installingWorker's environment settings object's global object.
    4. +
    5. Let extendLifetimePromises be an empty array.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
        4. +
        5. Set registration's installing worker to null.
        6. +
        7. Pop the top element from installation queue and installation result handle queue.
        8. +
        9. If the result of running Get Newest Worker algorithm is null, then: +
            +
          1. Invoke Clear Registration algorithm passing registration as its argument.
          2. +
          +
        10. +
        11. Abort these steps.
        12. +
        +
      2. +
      3. Let eventObject be the first argument passed to this event listener.
      4. +
      5. Append eventObject's extend lifetime promises to extendLifetimePromises.
      6. +
      +
    8. +
    9. Let p be waiting for all of extendLifetimePromises.
    10. +
    11. Run the following substeps in parallel: +
        +
      1. Wait until p settles.
      2. +
      3. If p rejected, then: +
          +
        1. Set installFailed to true.
        2. +
        +
      4. +
      5. Else if p resolved with a value, then: +
          +
        1. Do nothing.
        2. +
        +
      6. +
      +
    12. +
    +
  22. +
  23. Pop the top element from installation queue.
  24. +
  25. CheckResultHandlePriority: If the value of the top element of installation result handle queue is not timeStamp, then: +
      +
    1. Wait until the top element of installation result handle queue is popped.
    2. +
    3. Jump to the step labeled CheckResultHandlePriority.
    4. +
    +

    Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

    +

    If task is discarded or the script has been aborted by the termination of installingWorker, set installFailed to true.

    +
  26. +
  27. Wait for task to have executed or been discarded.
  28. +
  29. If registration's installing worker is null, then: +
      +
    1. Abort these steps.
    2. +
    +
  30. +
  31. If installFailed is true, then: +
      +
    1. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    2. +
    3. Set registration's installing worker to null.
    4. +
    5. If the result of running Get Newest Worker algorithm is null, then: +
        +
      1. Invoke Clear Registration algorithm passing registration as its argument.
      2. +
      +
    6. +
    7. Abort these steps.
    8. +
    +
  32. +
  33. If registration's waiting worker is not null, then: +
      +
    1. Terminate registration's waiting worker.
    2. +
    3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
    4. +
    5. The user agent may abort in-flight requests triggered by registration's waiting worker.
    6. +
    +
  34. +
  35. Set registration's waiting worker to registration's installing worker.
  36. +
  37. Set registration's installing worker to null.
  38. +
  39. Run the Update State algorithm passing registration's waiting worker and installed as the arguments.
  40. +
  41. If registration's uninstalling flag is set, then: +
      +
    1. If it was set before timeStamp, unset registration's uninstalling flag.
    2. +
    3. Else, abort these steps.
    4. +
    +
  42. +
  43. If registration's waiting worker's skip waiting flag is set, then: +
      +
    1. For each service worker client serviceWorkerClient whose creation url matches registration's scope url: +
        +
      1. Let exitingWorker be the active worker that controls serviceWorkerClient.
      2. +
      3. If exitingWorker is not null, then: +
          +
        1. Wait for exitingWorker to finish handling any in-progress requests. +
        2. +
        3. Terminate exitingWorker.
        4. +
        5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
        6. +
        +
      4. +
      +
    2. +
    3. Run Activate algorithm, or its equivalent, passing registration as the argument.
    4. +
    5. Abort these steps.
    6. +
    +
  44. +
  45. Pop the top element from installation result handle queue.
  46. +
  47. Wait until no service worker client is using registration or registration's waiting worker's skip waiting flag is set.
  48. +
  49. If registration's waiting worker waitingWorker is not null and waitingWorker's skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument.
  50. +
+
+
+ +
9.5

Activate

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Generate a timestamp and let timeStamp be the result value.
  2. +
  3. Push timeStamp to activation queue.
  4. +
  5. CheckPriority: If the value of the top element of activation queue is not timeStamp, then: +
      +
    1. Wait until the top element of activation queue is popped.
    2. +
    3. Jump to the step labeled CheckPriority.
    4. +
    +

    Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

    +
  6. +
  7. Let activatingWorker be registration's waiting worker.
  8. +
  9. Let exitingWorker be registration's active worker.
  10. +
  11. If activatingWorker is null, then: +
      +
    1. Pop the top element from activation queue.
    2. +
    3. Abort these steps.
    4. +
    +
  12. +
  13. If exitingWorker is not null, then: +
      +
    1. Wait for exitingWorker to finish handling any in-progress requests. +
    2. +
    3. Terminate exitingWorker.
    4. +
    5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
    6. +
    +
  14. +
  15. Set registration's active worker to activatingWorker.
  16. +
  17. Set registration's waiting worker to null.
  18. +
  19. Run the Update State algorithm passing registration's active worker and activating as the arguments.
  20. +
  21. For each service worker client client whose creation url matches registration's scope url: +
      +
    1. If client is a window client, then: +
        +
      1. Unassociate client's responsible document from its application cache, if it has one.
      2. +
      +
    2. +
    3. Else if client is a shared worker client, then: +
        +
      1. Unassociate client's global object from its application cache, if it has one.
      2. +
      +
    4. +
    +

    Resources will now use the service worker registration instead of the existing application cache.

    +
  22. +
  23. For each service worker client client who is using registration: +
      +
    1. Set client's active worker to registration's active worker.
    2. +
    3. Invoke Notify Controller Change algorithm with client as the argument.
    4. +
    +
  24. +
  25. Let activeWorker be registration's active worker.
  26. +
  27. Invoke Run Service Worker algorithm with activeWorker as the arguement.
  28. +
  29. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the ExtendableEvent interface, with the event type activate, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Dispatch e at activeWorker's environment settings object's global object.
    4. +
    5. Let extendLifetimePromises be an empty array.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, report the error for the script per the runtime script errors handling.
      2. +
      3. Let eventObject be the first argument passed to this event listener.
      4. +
      5. Append eventObject's extend lifetime promises to extendLifetimePromises.
      6. +
      +
    8. +
    9. Let p be waiting for all of extendLifetimePromises.
    10. +
    +
  30. +
  31. Wait for task to have executed and p defined in task has settled, or task to have been discarded or the script to have been aborted by the termination of activeWorker.
  32. +
  33. Run the Update State algorithm passing registration's active worker and activated as the arguments.
  34. +
  35. Pop the top element from activation queue.
  36. +
+
+
+ +
9.6

Run Service Worker

+ + +
+
+
Input
+
serviceWorker, a service worker
+
Output
+
None
+
+
    +
  1. Assert: serviceWorker has the script resource successfully fetched against its script url.
  2. +
  3. If serviceWorker is already running, abort these steps.
  4. +
  5. Let workerGlobalScope be a new ServiceWorkerGlobalScope object.
  6. + +
  7. Let workerEventLoop be a newly created event loop.
  8. +
  9. Let settingsObject be a new environment settings object whose algorithms are defined as follows: +
    +
    The script execution environments
    +
    When the environment settings object is created, for each language supported by the user agent, create an appropriate execution environment as defined by the relevant specification.
    +
    When a script execution environment is needed, return the appropriate one from those created when the environment settings object was created.
    +
    The global object
    +
    Return workerGlobalScope.
    +
    The responsible event loop
    +
    Return workerEventLoop.
    +
    The referrer source
    +
    Return serviceWorker's script url.
    +
    The API URL character encoding
    +
    Return UTF-8.
    +
    The API base URL
    +
    Return serviceWorker's script url.
    +
    The origin and effective script origin
    +
    Return its registering service worker client's origin.
    +
    +
  10. +
  11. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.
  12. +
  13. Let source be the result of running the UTF-8 decode algorithm on the script resource of serviceWorker.
  14. +
  15. Let language be JavaScript.
  16. +
  17. In the newly created execution environment, create a JavaScript global environment whose global object is workerGlobalScope. (The JavaScript global environment whose global object is a ServiceWorkerGlobalScope object is defined as the service worker environment, which is a type of worker environments.)
  18. +
  19. Let script be a new script.
  20. +
  21. Obtain the appropriate script execution environment for the scripting language language from settingsObject.
  22. +
  23. Parse/compile/initialize source using that script execution environment, as appropriate for language, and thus obtain a code entry-point. If the script was not compiled successfully, let the code entry-point be a no-op script, and act as if a corresponding uncaught script error had occurred.
  24. +
  25. Let script's settings object be settingsObject.
  26. +
  27. Jump to the script's code entry-point, and let that run until it either returns, fails to catch an exception, or gets aborted by the kill a worker or terminate a worker algorithms.
  28. +
  29. Run the responsible event loop specified by settingsObject until it is destroyed.
  30. +
  31. Empty workerGlobalScope's list of active timers.
  32. +
+
+
+ +
9.7

Handle Fetch

+ + +

The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

+ +
+
+
Input
+
request, a request
+
Output
+
response, a response
+
+
    +
  1. Let handleFetchFailed be false.
  2. +
  3. Let respondWithEntered be false.
  4. +
  5. Let eventCanceled be false.
  6. +
  7. Let r be a new Request object associated with request.
  8. +
  9. Let headersObject be r's headers attribute value.
  10. +
  11. Set headersObject's guard to immutable.
  12. +
  13. Let response be null.
  14. +
  15. Let registration be null.
  16. +
  17. Let client be request's client.
  18. +
  19. Assert: request's context is not "serviceworker".
  20. +
  21. If request is a potential client request, then: +
      +
    1. Return null.
    2. +
    +
  22. +
  23. Else if request is a client request, then: +

    If the client request is under the scope of a service worker registration, appplication cache is completely bypassed regardless of whether the client request uses the service worker registration.

    +

    This behavior requires changing the algorithm steps in HTML: Issue 27482.

    +
      +
    1. If the navigation triggering request was initiated with a shift+reload or equivalent, then: +
        +
      1. Return null.
      2. +
      +
    2. +
    3. If request's context is "iframe" and request's url is local, then: +
        +
      1. If client's responsible browsing context's parent browsing context's Window object's service worker client's active worker activeWorker is not null, set registration to activeWorker's containing service worker registration.
      2. +
      +
    4. +
    5. Else: +
        +
      1. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing request's url as the argument.
      2. +
      +
    6. +
    7. If registration is null or registration's active worker is null, return null.
    8. +
    9. Set client's active worker to registration's active worker.
    10. +
    +

    From this point, the service worker client starts to use its active worker's containing service worker registration.

    +
  24. +
  25. Else if request is a resource request, then: +
      +
    1. If client's active worker is non-null, then: +
        +
      1. Set registration to client's active worker's containing service worker registration.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Return null.
      2. +
      +
    4. +
    +
  26. +
  27. Let activeWorker be registration's active worker.
  28. +
  29. If activeWorker's state is activating, then: +
      +
    1. Wait for activeWorker's state to become activated.
    2. +
    +
  30. +
  31. Assert: activeWorker is not null, and its state is activated.
  32. +
  33. Invoke Run Service Worker algorithm with activeWorker as the arguement.
  34. +
  35. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the FetchEvent interface, with the event type fetch, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Let the request attribute of e be initialized to r.
    4. +
    5. Let c be null.
    6. +
    7. If request's client is a window client, set c to the result of running Capture Window Client algorithm, or its equivalent, with request's client's responsible browsing context as the argument.
    8. +
    9. Else, set c to a Client object that represents request's client.
    10. +
    11. Let the client attribute of e be initialized to c.
    12. +
    13. Let the isReload attribute of e be initialized to true if request's client is a window client and the event was dispatched with the user's intention for the page reload, and false otherwise.
    14. +
    15. Dispatch e at activeWorker's environment settings object's global object.
    16. +
    17. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      3. Let event be the event for which this event listener was invoked.
      4. +
      5. If event's respond-with entered flag is set, then: +
          +
        1. Set respondWithEntered to true.
        2. +
        +
      6. +
      7. If event's wait to respond flag is set, then: +
          +
        1. Wait until event's wait to respond flag is unset.
        2. +
        3. If event's respond-with error flag is set, then: +
            +
          1. Set handleFetchFailed to true.
          2. +
          +
        4. +
        5. Else: +
            +
          1. If the argument passed into the event's respondWith(r) method arg is a Response object, then: +
            1. Set response to arg.
            +
          2. +
          3. Else: +
              +
            1. Set response to the value which arg resolved with.
            2. +
            +
          4. +
          +
        6. +
        +
      8. +
      9. If event's canceled flag is set, then: +
          +
        1. Set eventCanceled to true.
        2. +
        +
      10. +
      +
    18. +
    +

    If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

    +
  36. +
  37. Wait for task to have executed or been discarded.
  38. +
  39. If respondWithEntered is false, then: +
      +
    1. If eventCanceled is true, then: +
        +
      1. Return a network error and run the following substeps in parallel.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Return null and run the following substeps in parallel.
      2. +
      +
    4. +
    5. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    6. +
    7. Abort these steps.
    8. +
    +
  40. +
  41. If handleFetchFailed is true, then: +
      +
    1. Return a network error and run the following substeps in parallel.
    2. +
    3. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    4. +
    +
  42. +
  43. Else: +
      +
    1. Return a response represented by response and run the following substeps in parallel.
    2. +
    3. If request is a client request, then: +
        +
      1. Invoke Soft Update algorithm, or its equivalent, with registration.
      2. +
      +
    4. +
    +
  44. +
+
+
+ +
9.8

Handle Functional Event

+ + +
+
+
Input
+
registration, a service worker registration
+
callbackSteps, an algorithm
+
Output
+
None
+
+
    +
  1. Assert: a Record with the [[value]] equals to registration is contained in scope to registration map.
  2. +
  3. Assert: registration's active worker is not null.
  4. +
  5. Let activeWorker be registration's active worker.
  6. +
  7. Invoke Run Service Worker algorithm with activeWorker as the arguement.
  8. +
  9. Queue a task to invoke callbackSteps with activeWorker's environment settings object's global object as its argument. +

    The task must use the DOM manipulation task source.

    +
  10. +
+
+
+ +
9.9

Handle Service Worker Client Unload

+ + +

The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

+ +
+
+
Input
+
client, a service worker client
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be the service worker registration used by client.
  4. +
  5. If registration is null, then: +
      +
    1. Abort these steps.
    2. +
    +
  6. +
  7. If any other service worker client is using registration, then: +
      +
    1. Abort these steps.
    2. +
    +
  8. +
  9. If registration's uninstalling flag is true, then: +
      +
    1. Invoke Clear Registration algorithm passing registration as its argument.
    2. +
    3. Abort these steps.
    4. +
    +
  10. +
  11. If registration's waiting worker is not null: +
      +
    1. Run Activate algorithm, or its equivalent, with registration at the argument.
    2. +
    +
  12. +
+
+
+ +
9.10

Unregister

+ + +
+
+
Input
+
client, a service worker client
+
scope, an absolute URL
+
Output
+
promise, a promise
+
+
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. If the origin of scope is not client's origin, then: +
        +
      1. Reject promise with a "SecurityError" exception.
      2. +
      3. Abort these steps.
      4. +
      +
    2. +
    3. Let registration be the result of running Get Registration algorithm passing scope as the argument.
    4. +
    5. If registration is null, then: +
        +
      1. Resolve promise with false.
      2. +
      3. Abort these steps.
      4. +
      +
    6. +
    7. Set registration's uninstalling flag.
    8. +
    9. Resolve promise with true.
    10. +
    11. If no service worker client is using registration, then: +
        +
      1. If registration's uninstalling flag is unset, then: +
          +
        1. Abort these steps.
        2. +
        +
      2. +
      3. Invoke Clear Registration algorithm passing registration as its argument.
      4. +
      +
    12. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
9.11

Set Registration

+ + +
+
+
Input
+
scope, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let scopeString be serialized scope with the exclude fragment flag set.
  4. +
  5. Let registration be a new service worker registration whose scope url is set to scope.
  6. +
  7. Set a newly-created Record {[[key]]: scopeString, [[value]]: registration} to scope to registration map.
  8. +
  9. Return registration.
  10. +
+
+
+ +
9.12

Clear Registration

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. If registration's installing worker is not null, then: +
      +
    1. Terminate registration's installing worker.
    2. +
    3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    4. +
    5. Set registration's installing worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's installing worker.
    8. +
    +
  4. +
  5. If registration's waiting worker is not null, then: +
      +
    1. Terminate registration's waiting worker.
    2. +
    3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
    4. +
    5. Set registration's waiting worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's waiting worker.
    8. +
    +
  6. +
  7. If registration's active worker is not null, then: +
      +
    1. Terminate registration's active worker.
    2. +
    3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
    4. +
    5. Set registration's active worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's active worker.
    8. +
    +
  8. +
  9. Delete a Record {[[key]], [[value]]} entry of its scope to registration map where registration's scope url matches entry.[[key]].
  10. +
+
+
+ +
9.13

Update State

+ + +
+
+
Input
+
worker, a service worker
+
state, a service worker's state
+
Output
+
None
+
+
    +
  1. Set worker's state to state.
  2. +
  3. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker.
  4. +
  5. For each serviceWorker in serviceWorkers: +
      +
    1. Queue a task to fire a simple event named statechange at serviceWorker.
    2. +
    +

    The task must use serviceWorker's service worker client's responsible event loop and the DOM manipulation task source.

    +
  6. +
+
+
+ +
9.14

Notify Controller Change

+ + +
+
+
Input
+
client, a service worker client
+
Output
+
None
+
+
    +
  1. Assert: client is not null.
  2. +
  3. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with.
  4. +
+

The task must use client's responsible event loop and the DOM manipulation task source.

+
+
+ +
9.15

Match Service Worker Registration

+ + +
+
+
Input
+
clientURL, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let clientURLString be serialized clientURL.
  4. +
  5. Let matchingScope be the longest [[key]] in scope to registration map starting with the value of clientURLString.
  6. +
  7. Let matchingScopeURL be the result of parsing matchingScope.
  8. +
  9. Let registration be the result of running Get Registration algorithm passing matchingScopeURL as the argument.
  10. +
  11. If registration is not null and registration's uninstalling flag is set, then: +
      +
    1. Return null.
    2. +
    +
  12. +
  13. Return registration.
  14. +
+
+
+ +
9.16

Get Registration

+ + +
+
+
Input
+
scope, an absolute URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be null.
  4. +
  5. Let scopeString be serialized scope with the exclude fragment flag set.
  6. +
  7. For each Record {[[key]], [[value]]} entry of its scope to registration map: +
      +
    1. If scopeString matches entry.[[key]], then: +
        +
      1. Set registration to entry.[[value]].
      2. +
      +
    2. +
    +
  8. +
  9. Return registration.
  10. +
+
+
+ +
9.17

Get Newest Worker

+ + +
+
+
Input
+
registration, a service worker registration
+
Output
+
worker, a service worker
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let newestWorker be null.
  4. +
  5. If registration's installing worker is not null, then: +
      +
    1. Set newestWorker to registration's installing worker.
    2. +
    +
  6. +
  7. Else if registration's waiting worker is not null, then: +
      +
    1. Set newestWorker to registration's waiting worker.
    2. +
    +
  8. +
  9. Else if registration's active worker is not null, then: +
      +
    1. Set newestWorker to registration's active worker.
    2. +
    +
  10. +
  11. Return newestWorker.
  12. +
+
+
+ +
9.18

Capture Window Client

+ + +
+
+
Input
+
browsingContext, a browsing context
+
Output
+
windowClient, a WindowClient object
+
+
    +
  1. Let windowClient be a new WindowClient object that represents browsingContext.
  2. +
  3. Set windowClient's visibility state to browsingContext's active document's visibilityState attribute value.
  4. +
  5. Set windowClient's focus state to the result of running browsingContext's active document's hasFocus() method.
  6. +
  7. Return windowClient.
  8. +
+
+
+ +
9.19

Query Cache

+ + +
+
+
Input
+
request, a Request object
+
options, a CacheQueryOptions object, optional
+
targetStorage, an array that has [Request, Response] pairs as its elements, optional
+
Output
+
resultArray, an array that has [Request, Response] pairs as its elements
+
+
    +
  1. Let requestArray be an empty array.
  2. +
  3. Let responseArray be an empty array.
  4. +
  5. Let resultArray be an empty array.
  6. +
  7. If options.ignoreMethod is false and request.method is neither "GET" nor "HEAD", then: +
      +
    1. Return resultArray.
    2. +
    +
  8. +
  9. Let cachedURL and requestURL be null.
  10. +
  11. Let serializedCachedURL and serializedRequestURL be null.
  12. +
  13. If the optional argument targetStorage is omitted, then: +
      +
    1. For each fetching record entry of its request to response map, in key insertion order: +
        +
      1. Set cachedURL to entry.[[key]]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.ignoreSearch is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add a copy of entry.[[key]] to requestArray.
        2. +
        3. Add a copy of entry.[[value]] to responseArray.
        4. +
        +
      12. +
      +
    2. +
    +
  14. +
  15. Else: +
      +
    1. For each record in targetStorage: +
        +
      1. Set cachedURL to record[0]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.ignoreSearch is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add record[0] to requestArray.
        2. +
        3. Add record[1] to responseArray.
        4. +
        +
      12. +
      +
    2. +
    +
  16. +
  17. For each cachedResponse in responseArray with the index index: +
      +
    1. Let cachedRequest be the indexth element in requestArray.
    2. +
    3. If cachedResponse's response's header list contains no header named `Vary`, or options.ignoreVary is true, then: +
        +
      1. Add an array [cachedRequest, cachedResponse] to resultArray.
      2. +
      3. Continue to the next iteration of the loop.
      4. +
      +
    4. +
    5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
    6. +
    7. Let matchFailed be false.
    8. +
    9. For each f in varyHeaders: +
        +
      1. If f matches "*", or the result of running cachedRequest.headers object's get(name) method with f as the argument does not match the result of running request.headers object's get(name) method with f as the argument, then: +
          +
        1. Set matchFailed to true.
        2. +
        3. Break the loop.
        4. +
        +
      2. +
      +
    10. +
    11. If matchFailed is false, then: +
        +
      1. Add an array [cachedRequest, cachedResponse] to resultArray.
      2. +
      +
    12. +
    +
  18. +
  19. Return resultArray.
  20. +
+
+
+ +
9.20

Batch Cache Operations

+ + +
+
+
Input
+
operations, an array of CacheBatchOperation dictionary objects
+
Output
+
promise, a promise resolves with an array of Response objects.
+
+
    +
  1. Let p be a promise resolved with no value.
  2. +
  3. Return the result of transforming p with a fulfillment handler that performs the following substeps in parallel: +
      +
    1. Let itemsCopy be a new request to response map that is a copy of its context object's request to response map.
    2. +
    3. Let addedRecords be an empty array.
    4. +
    5. Try running the following substeps atomically: +
        +
      1. Let resultArray be an empty array.
      2. +
      3. For each operation in operations with the index index: +
          +
        1. If operation.type matches neither "delete" nor "put", then: +
            +
          1. Throw a TypeError.
          2. +
          +
        2. +
        3. If operation.type matches "delete" and operation.response is not null, then: +
            +
          1. Throw a TypeError.
          2. +
          +
        4. +
        5. If the result of running Query Cache algorithm passing operation.request, operation.options, and addedRecords as the arguments is not an empty array, then: +
            +
          1. Throw an "InvalidStateError" exception.
          2. +
          +
        6. +
        7. Let requestResponseArray be the result of running Query Cache algorithm passing operation.request and operation.options as the arguments.
        8. +
        9. For each requestResponse in requestResponseArray: +
            +
          1. If operation.type matches "delete", remove the corresponding fetching record from request to response map.
          2. +
          +
        10. +
        11. If operation.type matches "put", then: +
            +
          1. If operation.response is null, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          2. +
          3. Let r be operation.request's associated request.
          4. +
          5. If r's url's scheme is not one of "http" and "https", then: +
              +
            1. Throw a TypeError.
            2. +
            +
          6. +
          7. If r's method is not `GET`, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          8. +
          9. If operation.options is not null, then: +
              +
            1. Throw a TypeError.
            2. +
            +
          10. +
          11. If there exists a corresponding fetching record fetchingRecord for operation.request and operation.response in request to response map, set fetchingRecord.[[value]] to operation.response.
          12. +
          13. Else, set a newly-created fetching record {[[key]]: operation.request, [[value]]: operation.response} to request to response map. +

            The cache commit is allowed as long as the response's headers are available.

            +
          14. +
          15. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "QuotaExceededError" exception.
          16. +
          17. Add an array [operation.request, operation.response] to addedRecords.
          18. +
          +
        12. +
        13. Add operation.response to resultArray.
        14. +
        +
      4. +
      5. Return resultArray.
      6. +
      +
    6. +
    7. And then, if an exception was thrown, then: +
        +
      1. Set the context object's request to response map to itemsCopy.
      2. +
      3. Throw the exception
      4. +
      +
    8. +
    +
  4. +
+
+
+ +
+ +
10

Acknowledgements

+ + + +

Jake Archibald is a ghost-author of this document. The best instincts in the design are his. He similarly shaped many of the details through discussion and experimentation. The bits which are not his (but which are good) owe everything to his experience, persistence, and focus on enabling web developers. He embodies a hopeful example for developers in shaping browser efforts to more directly address real-world pain points. If service workers solve "offline for the web", the credit is due him.

+ +

Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

+ +

Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.

+ +

In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, and Hiroki Nakagawa.

+ +

Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

+ +

The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

+ +

Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.

+
+ + + diff --git a/service_worker.js b/service_worker.js deleted file mode 100644 index 8ce05065..00000000 --- a/service_worker.js +++ /dev/null @@ -1,857 +0,0 @@ -// This API proposal depends on: -// DOM: http://www.w3.org/TR/domcore/ -// URLs: http://url.spec.whatwg.org/ -// Promises: https://github.com/slightlyoff/DOMPromise/ -// Shared Workers: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#shared-workers -var __extends = this.__extends || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); -}; -// Semi-private to work around TS. Not for impl. -var _RegistrationOptions = (function () { - function _RegistrationOptions() { - this.scope = "/*"; - } - return _RegistrationOptions; -})(); - -/////////////////////////////////////////////////////////////////////////////// -// The Service Worker -/////////////////////////////////////////////////////////////////////////////// -var ExtendableEvent = (function (_super) { - __extends(ExtendableEvent, _super); - function ExtendableEvent() { - _super.apply(this, arguments); - } - // Delay treating the installing worker until the passed Promise resolves - // successfully. This is primarily used to ensure that an ServiceWorker is not - // active until all of the "core" Caches it depends on are populated. - ExtendableEvent.prototype.waitUntil = function (f) { - }; - return ExtendableEvent; -})(_Event); - -var InstallEvent = (function (_super) { - __extends(InstallEvent, _super); - function InstallEvent() { - _super.apply(this, arguments); - this.activeWorker = null; - } - return InstallEvent; -})(ExtendableEvent); - -var ServiceWorkerClients = (function () { - function ServiceWorkerClients() { - } - ServiceWorkerClients.prototype.getAll = function (options) { - return new Promise(function () { - // the objects returned will be new instances every time - }); - }; - return ServiceWorkerClients; -})(); - -var ServiceWorkerClient = (function () { - function ServiceWorkerClient(url) { - // attempt to open a new tab/window to url - } - return ServiceWorkerClient; -})(); - -// The scope in which worker code is executed -var ServiceWorkerGlobalScope = (function (_super) { - __extends(ServiceWorkerGlobalScope, _super); - function ServiceWorkerGlobalScope() { - _super.apply(this, arguments); - } - ServiceWorkerGlobalScope.prototype.fetch = function (request) { - // Notes: - // Promise resolves as soon as headers are available - // The Response object contains a toBlob() method that returns a - // Promise for the body content. - // The toBlob() promise will reject if the response is a OpaqueResponse. - return new Promise(function (r) { - r.resolve(_defaultToBrowserHTTP(request)); - }); - }; - return ServiceWorkerGlobalScope; -})(WorkerGlobalScope); - -/////////////////////////////////////////////////////////////////////////////// -// Event Worker APIs -/////////////////////////////////////////////////////////////////////////////// -// http://fetch.spec.whatwg.org/#requests -var Request = (function () { - function Request(params) { - // see: http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - this.timeout = 0; - this.method = "GET"; - // FIXME: we only provide async! - this.synchronous = false; - this.forcePreflight = false; - this.omitCredentials = false; - if (params) { - if (typeof params.timeout != "undefined") { - this.timeout = params.timeout; - } - if (typeof params.url != "undefined") { - this.url = params.url; - } - if (typeof params.synchronous != "undefined") { - this.synchronous = params.synchronous; - } - if (typeof params.forcePreflight != "undefined") { - this.forcePreflight = params.forcePreflight; - } - if (typeof params.omitCredentials != "undefined") { - this.omitCredentials = params.omitCredentials; - } - if (typeof params.method != "undefined") { - this.method = params.method; - } - if (typeof params.headers != "undefined") { - this.headers = params.headers; - } - if (typeof params.body != "undefined") { - this.body = params.body; - } - } - } - return Request; -})(); - -// http://fetch.spec.whatwg.org/#responses -var AbstractResponse = (function () { - function AbstractResponse() { - } - return AbstractResponse; -})(); - -var OpaqueResponse = (function (_super) { - __extends(OpaqueResponse, _super); - function OpaqueResponse() { - _super.apply(this, arguments); - } - Object.defineProperty(OpaqueResponse.prototype, "url", { - get: // This class represents the result of cross-origin fetched resources that are - // tainted, e.g. - function () { - return ""; - }, - enumerable: true, - configurable: true - }); - return OpaqueResponse; -})(AbstractResponse); - -var Response = (function (_super) { - __extends(Response, _super); - function Response(params) { - if (params) { - if (typeof params.status != "undefined") { - this.status = params.status; - } - if (typeof params.statusText != "undefined") { - this.statusText = params.statusText; - } - if (typeof params.headers != "undefined") { - this.headers = params.headers; - } - /* - // FIXME: What do we want to do about passing in the body? - if (typeof params.body != "undefined") { - this.body = params.body; - } - */ - } - _super.call(this); - } - Object.defineProperty(Response.prototype, "headers", { - get: function () { - // TODO: outline the whitelist of readable headers - return this._headers; - }, - set: function (items) { - var _this = this; - if (items instanceof Map) { - items.forEach(function (value, key, map) { - return _this._headers.set(key, value); - }); - } else { - for (var x in items) { - (function (x) { - if (items.hasOwnProperty(x)) { - this._headers.set(x, items[x]); - } - }).call(this, x); - } - } - }, - enumerable: true, - configurable: true - }); - - Response.prototype.toBlob = function () { - return accepted(new Blob()); - }; - - Response.redirect = // http://fetch.spec.whatwg.org/#dom-response-redirect - function (url, status) { - return new Response(); - }; - return Response; -})(AbstractResponse); - -var CORSResponse = (function (_super) { - __extends(CORSResponse, _super); - function CORSResponse() { - _super.apply(this, arguments); - } - return CORSResponse; -})(Response); - -var FetchEvent = (function (_super) { - __extends(FetchEvent, _super); - function FetchEvent() { - _super.call(this, "fetch", { cancelable: true, bubbles: false }); - // Has the user provided intent for the page to be reloaded fresher than - // their current view? Eg: pressing the refresh button - // Clicking a link & hitting back shouldn't be considered a reload. - // Ctrl+l enter: Left to the UA to decide - this.isReload = false; - - // This is the meat of the API for most use-cases. - // If preventDefault() is not called on the event, the request is sent to - // the default browser worker. That is to say, to respond with something - // from the cache, you must preventDefault() and respond with it manually, - // digging the resource out of the cache and calling - // evt.respondWith(cachedItem). - // - // Note: - // while preventDefault() must be called synchronously to cancel the - // default, responding does not need to be synchronous. That is to say, - // you can do something async (like fetch contents, go to IDB, whatever) - // within whatever the network time out is and as long as you still have - // the FetchEvent instance, you can fulfill the request later. - this.client = null; - } - // * If a Promise is provided, it must resolve with a Response, else a - // Network Error is thrown. - // * If the request isTopLevel navigation and the return value - // is a CrossOriginResponse (an opaque response body), a Network Error is - // thrown. - // * The final URL of all successful (non network-error) responses is - // the *requested* URL. - // * Renderer-side security checks about tainting for - // x-origin content are tied to the transparency (or opacity) of - // the Response body, not URLs. - // - // respondWith(r: Promise) : void; - // respondWith(r: Response) : void; - FetchEvent.prototype.respondWith = function (r) { - if (!(r instanceof Response) || !(r instanceof Promise)) { - throw new Error("Faux NetworkError because DOM is currently b0rken"); - } - - this.stopImmediatePropagation(); - - if (r instanceof Response) { - r = new Promise(function (resolver) { - resolver.resolve(r); - }); - } - r.then(_useWorkerResponse, _defaultToBrowserHTTP); - }; - - // "any" to make the TS compiler happy: - FetchEvent.prototype.forwardTo = function (url) { - if (!(url instanceof _URL) || typeof url != "string") { - throw new Error("Faux NetworkError because DOM is currently b0rken"); - } - - this.stopImmediatePropagation(); - - return new Promise(function (resolver) { - resolver.resolve(Response.redirect(url.toString(), { - status: 302 - })); - }); - }; - - // event.default() returns a Promise, which resolves to… - // If it's a navigation - // If the response is a redirect - // It resolves to a OpaqueResponse for the redirect - // This is tagged with "other supermagic only-for-this happytime", meaning - // this request cannot be used for anything other than a response for this - // request (cannot go into cache) - // Else resolves as fetch(event.request) - // Else - // Follow all redirects - // Tag response as "supermagic change url" - // When the page receives this response it should update the resource url to - // the response url (for base url construction etc) - FetchEvent.prototype.default = function () { - return accepted(); - }; - return FetchEvent; -})(_Event); - -// Design notes: -// - Caches are atomic: they are not complete until all of their resources are -// fetched -// This largely describes the current Application Cache API. It's only available -// inside worker instances (not in regular documents), meaning that caching is a -// feature of the event worker. This is likely to change! -var Cache = (function () { - function Cache() { - } - // also for spec purposes only - Cache.prototype._query = function (request, options) { - var ignoreSearch, ignoreMethod, ignoreVary, prefixMatch; - - if (options) { - ignoreSearch = options.ignoreSearch; - ignoreMethod = options.ignoreMethod; - ignoreVary = options.ignoreVary; - prefixMatch = options.prefixMatch; - } else { - ignoreSearch = false; - ignoreMethod = false; - ignoreVary = false; - prefixMatch = false; - } - - request = _castToRequest(request); - - if (!ignoreMethod && request.method !== 'GET' && request.method !== 'HEAD') { - // we only store GET responses at the moment, so no match - return []; - } - - var cachedRequests = this._items.keys().filter(function (cachedRequest) { - var cachedUrl = new _URL(cachedRequest.url); - var requestUrl = new _URL(request.url); - - if (ignoreSearch) { - cachedUrl.search = ''; - requestUrl.search = ''; - } - - if (prefixMatch) { - cachedUrl.href = cachedUrl.href.slice(0, requestUrl.href.length); - } - - return cachedUrl.href != cachedUrl.href; - }); - - var cachedResponses = cachedRequests.map(this._items.get.bind(this._items)); - var results = []; - - cachedResponses.forEach(function (cachedResponse, i) { - if (!cachedResponse.headers.has('vary') || ignoreVary) { - results.push([cachedRequests[i], cachedResponse]); - return; - } - - var varyHeaders = cachedResponse.headers.get('vary').split(','); - var varyHeader; - - for (var j = 0; j < varyHeaders.length; j++) { - varyHeader = varyHeaders[j].trim(); - - if (varyHeader == '*') { - continue; - } - - if (cachedRequests[i].headers.get(varyHeader) != request.headers.get(varyHeader)) { - return; - } - } - - results.push([cachedRequests[i], cachedResponse]); - }); - - return results; - }; - - Cache.prototype.match = function (request, options) { - // the UA may do something more optimal than this: - return this.matchAll(request, options).then(function (responses) { - return responses[0]; - }); - }; - - Cache.prototype.matchAll = function (request, options) { - var thisCache = this; - - return accepted().then(function () { - if (request) { - return thisCache._query(request, options).map(function (requestResponse) { - return requestResponse[1]; - }); - } else { - return thisCache._items.values(); - } - }); - }; - - Cache.prototype.add = function (request) { - return this.addAll([request]).then(function (responses) { - return responses[0]; - }).then(function (response) { - return undefined; - }); - }; - - Cache.prototype.addAll = function (requests) { - var thisCache = this; - requests = requests.map(_castToRequest); - - var responsePromises = requests.map(function (request) { - var requestURL = new _URL(request.url); - if ((requestURL.protocol !== 'http:') && (requestURL.protocol !== 'https:')) - return Promise.reject(new Error("Faux NetworkError")); - return fetch(request); - }); - - // wait for all our requests to complete - return Promise.all(responsePromises).then(function (responses) { - return thisCache._batch(responses.map(function (response, i) { - return { type: 'put', request: requests[i], response: response }; - })).then(function (responses) { - return undefined; - }); - }); - }; - - Cache.prototype.put = function (request, response) { - var thisCache = this; - - return this._batch([ - { type: 'put', request: request, response: response } - ]).then(function (results) { - return undefined; - }); - }; - - // delete zero or more entries - Cache.prototype.delete = function (request, options) { - return this._batch([ - { type: 'delete', request: request, options: options } - ]).then(function (results) { - if (results) { - return true; - } else { - return false; - } - }); - }; - - Cache.prototype.keys = function (request, options) { - var thisCache = this; - - return accepted().then(function () { - if (request) { - return thisCache._query(request, options).map(function (requestResponse) { - return requestResponse[0]; - }); - } else { - return thisCache._items.keys(); - } - }); - }; - - Cache.prototype._batch = function (operations) { - var thisCache = this; - - return Promise.resolve().then(function () { - var itemsCopy = thisCache._items; - var addedRequests = []; - - try { - return operations.map(function handleOperation(operation, i) { - if (operation.type != 'delete' && operation.type != 'put') { - throw TypeError("Invalid operation type"); - } - if (operation.type == "delete" && operation.response) { - throw TypeError("Cannot use response for delete operations"); - } - - var request = _castToRequest(operation.request); - var result = thisCache._query(request, operation.options).reduce(function (previousResult, requestResponse) { - if (addedRequests.indexOf(requestResponse[0]) !== -1) { - throw Error("Batch operation at index " + i + " overrode previous put operation"); - } - return thisCache._items.delete(requestResponse[0]) || previousResult; - }, false); - - if (operation.type == 'put') { - if (!operation.response) { - throw TypeError("Put operation must have a response"); - } - var requestURL = new _URL(request.url); - if ((requestURL.protocol !== 'http:') && (requestURL.protocol !== 'https:')) { - throw TypeError("Only http and https schemes are supported"); - } - if (request.method !== 'GET') { - throw TypeError("Only GET requests are supported"); - } - if (operation.options) { - throw TypeError("Put operation cannot have match options"); - } - if (!(operation.response instanceof AbstractResponse)) { - throw TypeError("Invalid response"); - } - - addedRequests.push(request); - thisCache._items.set(request, operation.response); - result = operation.response; - } - - return operation.response; - }); - } catch (err) { - // reverse the transaction - thisCache._items = itemsCopy; - throw err; - } - }); - }; - return Cache; -})(); - -var CacheStorage = (function () { - function CacheStorage() { - } - CacheStorage.prototype.match = function (request, options) { - var cacheName; - - if (options) { - cacheName = options["cacheName"]; - } - - var matchFromCache = function matchFromCache(cacheName) { - return this.open(cacheName).then(function (cache) { - return cache.match(request, options); - }); - }.bind(this); - - if (cacheName) { - return this.has(cacheName).then(function (hasCache) { - if (!hasCache) { - throw new Error("Not found"); - } - - return matchFromCache(cacheName); - }.bind(this)); - } - - return this.keys().then(function (cacheNames) { - var match; - - return cacheNames.reduce(function (chain, cacheName) { - return chain.then(function () { - return match || matchFromCache(cacheName).then(function (response) { - match = response; - }); - }); - }.bind(this), Promise.resolve()); - }); - }; - - CacheStorage.prototype.has = function (cacheName) { - cacheName = cacheName.toString(); - return Promise.resolve(this._items.has(cacheName)); - }; - - CacheStorage.prototype.open = function (cacheName) { - cacheName = cacheName.toString(); - - var cache = this._items.get(cacheName); - - if (!cache) { - cache = new Cache(); - this._items.set(cacheName, cache); - } - - return Promise.resolve(cache); - }; - - CacheStorage.prototype.delete = function (cacheName) { - cacheName = cacheName.toString(); - if (this._items.delete(cacheName)) { - return Promise.resolve(true); - } else { - return Promise.resolve(false); - } - }; - - CacheStorage.prototype.keys = function () { - return Promise.resolve(this._items.keys()); - }; - return CacheStorage; -})(); - -//////////////////////////////////////////////////////////////////////////////// -// Utility Decls to make the TypeScript compiler happy -//////////////////////////////////////////////////////////////////////////////// -// See: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts -var BroadcastChannel = (function () { - function BroadcastChannel(channelName) { - } - return BroadcastChannel; -})(); -; - -var WorkerGlobalScope = (function (_super) { - __extends(WorkerGlobalScope, _super); - function WorkerGlobalScope() { - _super.apply(this, arguments); - } - WorkerGlobalScope.prototype.setTimeout = function (handler, timeout) { - var args = []; - for (var _i = 0; _i < (arguments.length - 2); _i++) { - args[_i] = arguments[_i + 2]; - } - return 0; - }; - - WorkerGlobalScope.prototype.setInterval = function (handler, timeout) { - var args = []; - for (var _i = 0; _i < (arguments.length - 2); _i++) { - args[_i] = arguments[_i + 2]; - } - return 0; - }; - - // WindowTimerExtensions - WorkerGlobalScope.prototype.msSetImmediate = function (expression) { - var args = []; - for (var _i = 0; _i < (arguments.length - 1); _i++) { - args[_i] = arguments[_i + 1]; - } - return 0; - }; - - WorkerGlobalScope.prototype.setImmediate = function (expression) { - var args = []; - for (var _i = 0; _i < (arguments.length - 1); _i++) { - args[_i] = arguments[_i + 1]; - } - return 0; - }; - - // WindowBase64 - WorkerGlobalScope.prototype.btoa = function (rawString) { - return ""; - }; - WorkerGlobalScope.prototype.atob = function (encodedString) { - return ""; - }; - return WorkerGlobalScope; -})(_EventTarget); - -// Cause, you know, the stock definition claims that URL isn't a class. FML. -var _URL = (function () { - function _URL(url) { - } - Object.defineProperty(_URL.prototype, "search", { - get: function () { - return ""; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(_URL.prototype, "pathname", { - get: function () { - return ""; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(_URL.prototype, "href", { - get: function () { - return ""; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(_URL.prototype, "protocol", { - get: function () { - return ""; - }, - enumerable: true, - configurable: true - }); - return _URL; -})(); - -// http://tc39wiki.calculist.org/es6/map-set/ -// http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets -// http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts -// http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.14.4 -var _ES6Map = (function () { - function _ES6Map(iterable) { - } - _ES6Map.prototype.get = function (key) { - }; - _ES6Map.prototype.has = function (key) { - return true; - }; - _ES6Map.prototype.set = function (key, val) { - return new _ES6Map(); - }; - _ES6Map.prototype.clear = function () { - }; - _ES6Map.prototype.delete = function (key) { - return true; - }; - _ES6Map.prototype.forEach = function (callback, thisArg) { - }; - _ES6Map.prototype.entries = function () { - return []; - }; - _ES6Map.prototype.keys = function () { - return []; - }; - _ES6Map.prototype.values = function () { - return []; - }; - return _ES6Map; -})(); - -// the TS compiler is unhappy *both* with re-defining DOM types and with direct -// sublassing of most of them. This is sane (from a regular TS pespective), if -// frustrating. As a result, we describe the built-in Event type with a prefixed -// name so that we can subclass it later. -var _Event = (function () { - function _Event(type, eventInitDict) { - this.bubbles = false; - this.cancelable = true; - this.defaultPrevented = false; - this.isTrusted = false; - } - _Event.prototype.stopPropagation = function () { - }; - _Event.prototype.stopImmediatePropagation = function () { - }; - _Event.prototype.preventDefault = function () { - }; - return _Event; -})(); - -var _CustomEvent = (function (_super) { - __extends(_CustomEvent, _super); - // Constructor(DOMString type, optional EventInit eventInitDict - function _CustomEvent(type, eventInitDict) { - _super.call(this, type, eventInitDict); - } - return _CustomEvent; -})(_Event); - -var _EventTarget = (function () { - function _EventTarget() { - } - _EventTarget.prototype.dispatchEvent = function (e) { - return true; - }; - return _EventTarget; -})(); - -// https://github.com/slightlyoff/DOMPromise/blob/master/DOMPromise.idl -var Resolver = (function () { - function Resolver() { - } - Resolver.prototype.accept = function (v) { - }; - Resolver.prototype.reject = function (v) { - }; - Resolver.prototype.resolve = function (v) { - }; - return Resolver; -})(); - -var Promise = (function () { - // Callback type decl: - // callback : (n : number) => number - function Promise(init) { - } - Promise.prototype.then = function (fulfilled) { - return accepted(); - }; - - Promise.prototype.catch = function (rejected) { - return accepted(); - }; - - Promise.all = function () { - var stuff = []; - for (var _i = 0; _i < (arguments.length - 0); _i++) { - stuff[_i] = arguments[_i + 0]; - } - return accepted(); - }; - - Promise.resolve = function (val) { - return new Promise(function (r) { - r.accept(val); - }); - }; - - Promise.reject = function (err) { - return new Promise(function (r) { - r.reject(err); - }); - }; - return Promise; -})(); - -function accepted(v) { - if (typeof v === "undefined") { v = true; } - return new Promise(function (r) { - r.accept(true); - }); -} - -function acceptedResponse() { - return new Promise(function (r) { - r.accept(new Response()); - }); -} - -function fetch(url) { - return acceptedResponse(); -} - -// http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#shared-workers-and-the-sharedworker-interface -var SharedWorker = (function (_super) { - __extends(SharedWorker, _super); - function SharedWorker(url, name) { - _super.call(this); - } - return SharedWorker; -})(_EventTarget); - -//////////////////////////////////////////////////////////////////////////////// -// Not part of any public standard but used above: -//////////////////////////////////////////////////////////////////////////////// -var _useWorkerResponse = function () { - return accepted(); -}; -var _defaultToBrowserHTTP = function (url) { - return accepted(); -}; - -function _castToRequest(request) { - if (!(request instanceof Request)) { - request = new Request({ - 'url': new _URL(request).href - }); - } - return request; -} diff --git a/service_worker.ts b/service_worker.ts deleted file mode 100644 index 91ad65ff..00000000 --- a/service_worker.ts +++ /dev/null @@ -1,1048 +0,0 @@ -// This API proposal depends on: -// DOM: http://www.w3.org/TR/domcore/ -// URLs: http://url.spec.whatwg.org/ -// Promises: https://github.com/slightlyoff/DOMPromise/ -// Shared Workers: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#shared-workers - -//////////////////////////////////////////////////////////////////////////////// -// Document APIs -//////////////////////////////////////////////////////////////////////////////// - -interface RegistrationOptions { - scope: string; -} -// Semi-private to work around TS. Not for impl. -class _RegistrationOptions implements RegistrationOptions { - scope = "/*"; -} - -interface ServiceWorkerContainer extends EventTarget { - controller?: ServiceWorker; // the worker handling resource requests for this page - - // This atribute returns a Promise that resolves when this document - // has a controller - ready: Promise; // Promise - - // Returns a Promise - register(url: string, options?: _RegistrationOptions): Promise; - - // Returns a Promise - getRegistration(docURL?:string): Promise; - // docURL defaults to location.href - // Resolves with the ServiceWorkerRegistration that controls docURL or undefined if none is found - // Rejects with DOMError SecurityError if docURL is cross origin - - // Returns a Promise> - getRegistrations(): Promise; - // Resolves with an array of all ServiceWorkerRegistrations for the origin. - // Resolves with an empty array if none exist. - - oncontrollerchange: (ev: Event) => any; - // Fires when .controller changes - - onerror: (ev: ErrorEvent) => any; - // Called for any error from the active or installing SW's - // FIXME: allow differentiation between active and installing SW's - // here, perhaps via .worker? -} - -// extensions to window.navigator and self.navigator -interface NavigatorServiceWorker { - // null if page has no activated worker - serviceWorker: ServiceWorkerContainer; -} - -interface Navigator extends - NavigatorServiceWorker, - EventTarget, - // the rest is just stuff from the default ts definition - NavigatorID, - NavigatorOnLine, - // NavigatorDoNotTrack, - // NavigatorAbilities, - NavigatorGeolocation - // MSNavigatorAbilities -{ } - -interface ServiceWorkerRegistration extends EventTarget { - installing?: ServiceWorker; // worker undergoing the install process - waiting?: ServiceWorker; // installed worker, waiting to become active - active?: ServiceWorker; // the activating/activated worker, can be used as a controller - - // The registration pattern that matched this SW instance. E.g., if the - // following registrations are made: - // navigator.serviceWorker.register("serviceworker.js", "/foo/"); - // navigator.serviceWorker.register("serviceworker.js", "/bar/"); - // And the user navigates to http://example.com/foo/index.html, - // self.scope == "/foo/" - // SW's can use this to disambiguate which context they were started from. - scope: string; - - // Ping the server for an updated version of this registration, without - // consulting caches. Conceptually the same operation that SW's do max once - // every 24 hours. - update: () => void; - - unregister(): Promise; - // Unregisters this registration. - // Resolves with boolean value. - - onupdatefound: (ev: Event) => any; - // Fires when .installing becomes a new worker -} - -interface ServiceWorker extends Worker, AbstractWorker { - // Provides onerror, postMessage, etc. - scriptURL: string; - state: string; // "installing" -> "installed" -> "activating" -> "activated" -> "redundant" - onstatechange: (ev: Event) => any; -} - -declare var ServiceWorker: { - prototype: ServiceWorker; -} - -/////////////////////////////////////////////////////////////////////////////// -// The Service Worker -/////////////////////////////////////////////////////////////////////////////// -class ExtendableEvent extends _Event { - // Delay treating the installing worker until the passed Promise resolves - // successfully. This is primarily used to ensure that an ServiceWorker is not - // active until all of the "core" Caches it depends on are populated. - waitUntil(f: Promise): void {} -} - -class InstallEvent extends ExtendableEvent { - activeWorker: ServiceWorker = null; -} - -interface InstallEventHandler { (e:InstallEvent); } -interface ActivateEventHandler { (e:ExtendableEvent); } -interface FetchEventHandler { (e:FetchEvent); } - -// FIXME: need custom event types! -interface BeforeCacheEvictionEventHandler { (e:_Event); } -interface CacheEvictionEventHandler { (e:_Event); } - -interface OnlineEventHandler { (e:_Event); } -interface OfflineEventHandler { (e:_Event); } - -class ServiceWorkerClients { - getAll(options?: ServiceWorkerClientQueryOptions): Promise { // Promise for Array - return new Promise(function() { - // the objects returned will be new instances every time - }); - } -} - -interface ServiceWorkerClientQueryOptions { - includeUncontrolled: boolean; -} - -class ServiceWorkerClient { - constructor(url: string) { - // attempt to open a new tab/window to url - } - - // fulfills with no value if window/tab opens and can receive messages - // rejects if the above fails (with error) - // read-only - ready: Promise; - - // http://www.w3.org/TR/page-visibility/#dom-document-visibilitystate - // this value does not change after object creation, it's a snapshot - // read-only - visibilityState: string; // { "hidden", "visible", "prerender", "unloaded" } - - // http://www.whatwg.org/specs/web-apps/current-work/multipage/interaction.html#dom-document-hasfocus - // this value does not change after object creation, it's a snapshot - // read-only - focused: boolean; - - // this value does not change after object creation, it's a snapshot - // read-only - url: string; - - // http://fetch.spec.whatwg.org/#concept-request-context-frame-type - // so we can tell the difference between page, iframe & worker - // read-only - frameType: string; - - postMessage: (message: any, targetOrigin: string, ports?: any) => void; - - // rejects if client is gone, not yet ready, or cannot be focused for some other reason - // fulfills when client gains focus, or is already focused - focus: () => Promise; -} - -// The scope in which worker code is executed -class ServiceWorkerGlobalScope extends WorkerGlobalScope { - - self: ServiceWorkerGlobalScope; - caches: CacheStorage; - scriptCache: Cache; - - // A container for a list of ServiceWorkerClient objects that correspond to - // browsing contexts (or shared workers) that are on the origin of this SW - clients: ServiceWorkerClients; - registration: ServiceWorkerRegistration; - - skipWaiting: () => Promise; - - // - // Events - // - - // "online" and "offline" events are deliveredy via the WorkerGlobalScope - // contract: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#workerglobalscope - - // New Events - - // Called when a worker is downloaded and being setup to handle - // events (navigations, alerts, etc.) - oninstall: InstallEventHandler; - - // Called when a worker becomes the active event worker for a mapping - onactivate: ActivateEventHandler; - - // Called whenever this worker is meant to decide the disposition of a - // request. - onfetch: FetchEventHandler; - - onbeforeevicted: BeforeCacheEvictionEventHandler; - onevicted: CacheEvictionEventHandler; - - // ServiceWorkerGlobalScope objects act as if they had an implicit MessagePort - // associated with them. This port is part of a channel that is set up when - // the worker is created, but it is not exposed. This object must never be - // garbage collected before the ServiceWorkerGlobalScope object. - // All messages received by that port must immediately be retargeted at the - // ServiceWorkerGlobalScope object. - // The ev.source of these MessageEvents are instances of ServiceWorkerClient - onmessage: (ev: MessageEvent) => any; - - // FIXME(slightlyoff): Need to add flags for: - // - custom "accept/reject" handling, perhaps with global config - // - flag to consult the HTTP cache first? - fetch(request:Request); - fetch(request:string); // a URL - - fetch(request:any) : Promise { - // Notes: - // Promise resolves as soon as headers are available - // The Response object contains a toBlob() method that returns a - // Promise for the body content. - // The toBlob() promise will reject if the response is a OpaqueResponse. - return new Promise(function(r) { - r.resolve(_defaultToBrowserHTTP(request)); - }); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Event Worker APIs -/////////////////////////////////////////////////////////////////////////////// - -// http://fetch.spec.whatwg.org/#requests -class Request { - constructor(params?) { - if (params) { - if (typeof params.timeout != "undefined") { - this.timeout = params.timeout; - } - if (typeof params.url != "undefined") { - this.url = params.url; - } - if (typeof params.synchronous != "undefined") { - this.synchronous = params.synchronous; - } - if (typeof params.forcePreflight != "undefined") { - this.forcePreflight = params.forcePreflight; - } - if (typeof params.omitCredentials != "undefined") { - this.omitCredentials = params.omitCredentials; - } - if (typeof params.method != "undefined") { - this.method = params.method; - } - if (typeof params.headers != "undefined") { - this.headers = params.headers; - } - if (typeof params.body != "undefined") { - this.body = params.body; - } - } - } - - // see: http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - timeout: Number = 0; - url: string; - method: string = "GET"; - origin: string; - // FIXME: mode doesn't seem useful here. - mode: string; // Can be one of "same origin", "tainted cross-origin", "CORS", "CORS-with-forced-preflight" - // FIXME: we only provide async! - synchronous: boolean = false; - forcePreflight: boolean = false; - omitCredentials: boolean = false; - referrer: URL; - headers: Map; // Needs filtering! - body: any; /*TypedArray? String?*/ -} - -// http://fetch.spec.whatwg.org/#responses -class AbstractResponse { - constructor() {} -} - -class OpaqueResponse extends AbstractResponse { - // This class represents the result of cross-origin fetched resources that are - // tainted, e.g. - - get url(): string { return ""; } // Read-only for x-origin -} - -class Response extends AbstractResponse { - constructor(params?) { - if (params) { - if (typeof params.status != "undefined") { - this.status = params.status; - } - if (typeof params.statusText != "undefined") { - this.statusText = params.statusText; - } - if (typeof params.headers != "undefined") { - this.headers = params.headers; - } - /* - // FIXME: What do we want to do about passing in the body? - if (typeof params.body != "undefined") { - this.body = params.body; - } - */ - } - super(); - } - - // This class represents the result of all other fetched resources, including - // cross-origin fetched resources using the CORS fetching mode. - status: Number; - statusText: string; - // Explicitly omitting httpVersion - - // NOTE: the internal "_headers" is not meant to be exposed. Only here for - // pseudo-impl purposes. - _headers: Map; // FIXME: Needs filtering! - get headers() { - // TODO: outline the whitelist of readable headers - return this._headers; - } - set headers(items) { - if (items instanceof Map) { - items.forEach((value, key, map) => this._headers.set(key, value)) - } else { - // Enumerate own properties and treat them as key/value pairs - for (var x in items) { - (function(x) { - if (items.hasOwnProperty(x)) { this._headers.set(x, items[x]); } - }).call(this, x); - } - } - } - url: string; - toBlob(): Promise { return accepted(new Blob()); } - - // http://fetch.spec.whatwg.org/#dom-response-redirect - static redirect(url, status) { - return new Response(); - } -} - -class CORSResponse extends Response { - // TODO: slightlyoff: make CORS headers readable but not setable? - // TODO: outline the whitelist of readable headers -} - -class FetchEvent extends _Event { - // The body of the request. - request: Request; - - // The window issuing the request. - client: ServiceWorkerClient; - - // Has the user provided intent for the page to be reloaded fresher than - // their current view? Eg: pressing the refresh button - // Clicking a link & hitting back shouldn't be considered a reload. - // Ctrl+l enter: Left to the UA to decide - isReload: boolean = false; - - // * If a Promise is provided, it must resolve with a Response, else a - // Network Error is thrown. - // * If the request isTopLevel navigation and the return value - // is a CrossOriginResponse (an opaque response body), a Network Error is - // thrown. - // * The final URL of all successful (non network-error) responses is - // the *requested* URL. - // * Renderer-side security checks about tainting for - // x-origin content are tied to the transparency (or opacity) of - // the Response body, not URLs. - // - // respondWith(r: Promise) : void; - // respondWith(r: Response) : void; - respondWith(r: any) : void { // "any" to make the TS compiler happy: - if (!(r instanceof Response) || !(r instanceof Promise)) { - throw new Error("Faux NetworkError because DOM is currently b0rken"); - } - - this.stopImmediatePropagation(); - - if (r instanceof Response) { - r = new Promise(function(resolver) { resolver.resolve(r); }); - } - r.then(_useWorkerResponse, - _defaultToBrowserHTTP); - } - - forwardTo(url: string) : Promise; // treated as url - // "any" to make the TS compiler happy: - forwardTo(url: any) : Promise { - if (!(url instanceof _URL) || typeof url != "string") { - // Should *actually* be a DOMException.NETWORK_ERR - // Can't be today because DOMException isn't currently constructable - throw new Error("Faux NetworkError because DOM is currently b0rken"); - } - - this.stopImmediatePropagation(); - - return new Promise(function(resolver){ - resolver.resolve(Response.redirect(url.toString(), { - status: 302 - })); - }); - } - - // event.default() returns a Promise, which resolves to… - // If it's a navigation - // If the response is a redirect - // It resolves to a OpaqueResponse for the redirect - // This is tagged with "other supermagic only-for-this happytime", meaning - // this request cannot be used for anything other than a response for this - // request (cannot go into cache) - // Else resolves as fetch(event.request) - // Else - // Follow all redirects - // Tag response as "supermagic change url" - // When the page receives this response it should update the resource url to - // the response url (for base url construction etc) - default() : Promise { return accepted(); } - - constructor() { - super("fetch", { cancelable: true, bubbles: false }); - // This is the meat of the API for most use-cases. - // If preventDefault() is not called on the event, the request is sent to - // the default browser worker. That is to say, to respond with something - // from the cache, you must preventDefault() and respond with it manually, - // digging the resource out of the cache and calling - // evt.respondWith(cachedItem). - // - // Note: - // while preventDefault() must be called synchronously to cancel the - // default, responding does not need to be synchronous. That is to say, - // you can do something async (like fetch contents, go to IDB, whatever) - // within whatever the network time out is and as long as you still have - // the FetchEvent instance, you can fulfill the request later. - this.client = null; // to allow postMessage, window.topLevel, etc - } -} - -// Design notes: -// - Caches are atomic: they are not complete until all of their resources are -// fetched - -// This largely describes the current Application Cache API. It's only available -// inside worker instances (not in regular documents), meaning that caching is a -// feature of the event worker. This is likely to change! -class Cache { - // this is for spec purposes only, the browser will use something async and disk-based - _items: _ES6Map; - - constructor() { } - - // also for spec purposes only - _query(request: any, options?: CacheQueryOptions) : AbstractResponse[] { - var ignoreSearch, ignoreMethod, ignoreVary, prefixMatch; - - if (options) { - ignoreSearch = options.ignoreSearch; - ignoreMethod = options.ignoreMethod; - ignoreVary = options.ignoreVary; - prefixMatch = options.prefixMatch; - } else { - ignoreSearch = false; - ignoreMethod = false; - ignoreVary = false; - prefixMatch = false; - } - - request = _castToRequest(request); - - if (!ignoreMethod && - request.method !== 'GET' && - request.method !== 'HEAD') { - // we only store GET responses at the moment, so no match - return []; - } - - var cachedRequests = this._items.keys().filter(function(cachedRequest) { - var cachedUrl = new _URL(cachedRequest.url); - var requestUrl = new _URL(request.url); - - if (ignoreSearch) { - cachedUrl.search = ''; - requestUrl.search = ''; - } - - if (prefixMatch) { - cachedUrl.href = cachedUrl.href.slice(0, requestUrl.href.length); - } - - return cachedUrl.href != cachedUrl.href; - }); - - var cachedResponses = cachedRequests.map( - this._items.get.bind(this._items)); - var results = []; - - cachedResponses.forEach(function(cachedResponse: Response, i) { - if (!cachedResponse.headers.has('vary') || ignoreVary) { - results.push([cachedRequests[i], cachedResponse]); - return; - } - - var varyHeaders = cachedResponse.headers.get('vary').split(','); - var varyHeader; - - for (var j = 0; j < varyHeaders.length; j++) { - varyHeader = varyHeaders[j].trim(); - - if (varyHeader == '*') { - continue; - } - - // TODO(slighltyoff): should this treat headers case insensitive? - // TODO(slighltyoff): should comparison be more lenient than this? - if (cachedRequests[i].headers.get(varyHeader) != - request.headers.get(varyHeader)) { - return; - } - } - - results.push([cachedRequests[i], cachedResponse]); - }); - - return results; - } - - match(request:any, options?) : Promise { - // the UA may do something more optimal than this: - return this.matchAll(request, options).then(function(responses) { - return responses[0]; - }); - } - - matchAll(request?:any, options?) : Promise { - var thisCache = this; - - return accepted().then(function() { - if (request) { - return thisCache._query(request, options).map(function(requestResponse) { - return requestResponse[1]; - }); - } - else { - return thisCache._items.values(); - } - }); - } - - add(request:any) : Promise { - return this.addAll([request]).then(function(responses) { - return responses[0]; - }).then(function(response) { - return undefined; - }); - } - - addAll(requests:any[]) : Promise { - var thisCache = this; - requests = requests.map(_castToRequest); - - var responsePromises = requests.map(function(request) { - var requestURL = new _URL(request.url); - if ((requestURL.protocol !== 'http:') && - (requestURL.protocol !== 'https:')) - return Promise.reject(new Error("Faux NetworkError")); // "NetworkError" exception - return fetch(request); - }); - - // wait for all our requests to complete - return Promise.all(responsePromises).then(function(responses) { - return thisCache._batch(responses.map(function(response, i) { - return {type: 'put', request: requests[i], response: response}; - })).then(function(responses) { - return undefined; - }); - }); - } - - put(request:any, response:AbstractResponse) : Promise { - var thisCache = this; - - return this._batch([ - {type: 'put', request: request, response: response} - ]).then(function(results) { - return undefined; - }); - } - - // delete zero or more entries - delete(request: any, options?: CacheQueryOptions) : Promise { - return this._batch([ - {type: 'delete', request: request, options: options} - ]).then(function(results) { - if (results) { - return true; - } else { - return false; - } - }); - } - - keys(request?:any, options?: CacheQueryOptions): Promise { - var thisCache = this; - - return accepted().then(function() { - if (request) { - return thisCache._query(request, options).map(function(requestResponse) { - return requestResponse[0]; - }); - } - else { - return thisCache._items.keys(); - } - }); - } - - _batch(operations:any[]): Promise { - var thisCache = this; - - return Promise.resolve().then(function() { - var itemsCopy:_ES6Map = thisCache._items; - var addedRequests:Request[] = []; - - // the rest must be atomic - try { - return operations.map(function handleOperation(operation, i) { - if (operation.type != 'delete' && operation.type != 'put') { - throw TypeError("Invalid operation type"); - } - if (operation.type == "delete" && operation.response) { - throw TypeError("Cannot use response for delete operations"); - } - - var request = _castToRequest(operation.request); - var result = thisCache._query(request, operation.options).reduce(function(previousResult, requestResponse) { - if (addedRequests.indexOf(requestResponse[0]) !== -1) { - throw Error("Batch operation at index " + i + " overrode previous put operation"); - } - return thisCache._items.delete(requestResponse[0]) || previousResult; - }, false); - - if (operation.type == 'put') { - if (!operation.response) { - throw TypeError("Put operation must have a response"); - } - var requestURL = new _URL(request.url); - if ((requestURL.protocol !== 'http:') && - (requestURL.protocol !== 'https:')) { - throw TypeError("Only http and https schemes are supported"); - } - if (request.method !== 'GET') { - throw TypeError("Only GET requests are supported"); - } - if (operation.options) { - throw TypeError("Put operation cannot have match options"); - } - if (!(operation.response instanceof AbstractResponse)) { - throw TypeError("Invalid response"); - } - - addedRequests.push(request); - thisCache._items.set(request, operation.response); - result = operation.response; - } - - return operation.response; - }); - } catch(err) { - // reverse the transaction - thisCache._items = itemsCopy; - throw err; - } - }); - } -} - -interface CacheQueryOptions { - ignoreSearch: boolean; - ignoreMethod: boolean; - ignoreVary: boolean; - prefixMatch: boolean; - cacheName: string; -} - -interface CacheBatchOperation { - type: String; - request: Request; - response?: AbstractResponse; - options?: CacheQueryOptions; -} - -class CacheStorage { - // this is for spec purposes only, the browser will use something async and disk-based - _items: _ES6Map; - - constructor() { } - - match(request: any, options?: CacheQueryOptions): Promise { - var cacheName; - - if (options) { - cacheName = options["cacheName"]; - } - - var matchFromCache = function matchFromCache(cacheName) { - return this.open(cacheName).then(function(cache) { - return cache.match(request, options); - }); - }.bind(this); - - - if (cacheName) { - return this.has(cacheName).then(function(hasCache) { - if (!hasCache) { - throw new Error("Not found"); - } - - return matchFromCache(cacheName); - }.bind(this)); - } - - return this.keys().then(function(cacheNames) { - var match; - - return cacheNames.reduce(function(chain, cacheName) { - return chain.then(function() { - return match || matchFromCache(cacheName).then(function(response) { - match = response; - }); - }); - }.bind(this), Promise.resolve()); - }); - } - - has(cacheName: any): Promise { - cacheName = cacheName.toString(); - return Promise.resolve(this._items.has(cacheName)); - } - - open(cacheName: any): Promise { - cacheName = cacheName.toString(); - - var cache = this._items.get(cacheName); - - if (!cache) { - cache = new Cache(); - this._items.set(cacheName, cache); - } - - return Promise.resolve(cache); - } - - delete(cacheName: any): Promise { - cacheName = cacheName.toString(); - if (this._items.delete(cacheName)) { - return Promise.resolve(true); - } else { - return Promise.resolve(false); - } - } - - keys(): Promise { - return Promise.resolve(this._items.keys()); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Utility Decls to make the TypeScript compiler happy -//////////////////////////////////////////////////////////////////////////////// - -// See: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts -class BroadcastChannel { - constructor(channelName: string) {} - postMessage: (message: string) => void; - onmessage: (ev: MessageEvent) => any; -}; - -// See: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#workerglobalscope -interface WorkerLocation { - href: string; - protocol: string; - host: string; - hostname: string; - port: string; - pathname: string; - search: string; - hash: string; -} - -interface WorkerNavigator extends - NavigatorServiceWorker, - NavigatorID, - NavigatorOnLine { - // TODO(slightlyoff): ensure these are rolled into the HTML spec's WorkerNavigator! - // Extensions. See: https://github.com/slightlyoff/ServiceWorker/issues/122 - doNotTrack: string; - cookieEnabled: boolean; - mimeTypes: Array; -} - -interface WorkerUtils extends WindowTimers, WindowBase64 { - importScripts: (...urls: string[]) => void; - navigator: WorkerNavigator; -} - -class WorkerGlobalScope extends _EventTarget - implements WorkerUtils, AbstractWorker { - // AbstractWorker - onerror: (ev: ErrorEvent) => any; - - // WorkerUtils - importScripts: (...urls: string[]) => void; - navigator: WorkerNavigator; - - // WindowTimers - clearTimeout: (handle: number) => void; - setTimeout(handler: any, timeout?: any, ...args: any[]): number { - return 0; - } - clearInterval: (handle: number) => void; - setInterval(handler: any, timeout?: any, ...args: any[]): number { - return 0; - } - // WindowTimerExtensions - msSetImmediate(expression: any, ...args: any[]): number { return 0; } - clearImmediate: (handle: number) => void; - msClearImmediate: (handle: number) => void; - setImmediate(expression: any, ...args: any[]): number { return 0; } - - // WindowBase64 - btoa(rawString: string): string { return ""; } - atob(encodedString: string): string { return ""; } - - // Base API - self: WorkerGlobalScope; - location: WorkerLocation; - - close: () => void; - onoffline: Function; - ononline: Function; -} - -// Cause, you know, the stock definition claims that URL isn't a class. FML. -class _URL { - constructor(url:any) {} - get search() { return "" } - get pathname() { return "" } - get href() { return "" } - get protocol() { return "" } -} - -// http://tc39wiki.calculist.org/es6/map-set/ -// http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets -// http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts -// http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.14.4 -class _ES6Map implements Map { - // Base decl. - size: number; - constructor(iterable?:any[]) {} - get(key: K): any {} - has(key: K): boolean { return true; } - set(key: K, val: V): _ES6Map { return new _ES6Map() } - clear(): void {} - delete(key: K): boolean { return true; } - forEach(callback: Function, thisArg?: Object): void {} - entries(): any[] { return []; } - keys(): any[] { return []; } - values(): any[] { return []; } -} -/* -interface Map { - clear(): void; - delete(key: K): boolean; - forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void; - get(key: K): V; - has(key: K): boolean; - set(key: K, value: V): Map; - size: number; -} -declare var Map: { - new (): Map; -} - -class Map { - constructor(iterable?:any[]) {} - get(key: any): any {} - has(key: any): boolean { return true; } - set(key: any, val: any): void {} - clear(): void {} - delete(key: any): boolean { return true; } - forEach(callback: Function, thisArg?: Object): void {} - entries(): any[] { return []; } - keys(): any[] { return []; } - values(): any[] { return []; } -} -*/ - -// https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-event -interface EventHandler { (e:_Event); } -interface _EventInit { - bubbles: boolean; - cancelable: boolean; -} - -// the TS compiler is unhappy *both* with re-defining DOM types and with direct -// sublassing of most of them. This is sane (from a regular TS pespective), if -// frustrating. As a result, we describe the built-in Event type with a prefixed -// name so that we can subclass it later. -class _Event { - type: string; - target: any; - currentTarget: any; - eventPhase: Number; - bubbles: boolean = false; - cancelable: boolean = true; - defaultPrevented: boolean = false; - isTrusted: boolean = false; - timeStamp: Number; - stopPropagation(): void {} - stopImmediatePropagation(): void {} - preventDefault(): void {} - constructor(type : string, eventInitDict?: _EventInit) {} -} - -class _CustomEvent extends _Event { - // Constructor(DOMString type, optional EventInit eventInitDict - constructor(type : string, eventInitDict?: _EventInit) { - super(type, eventInitDict); - } -} - -class _EventTarget { - addEventListener: (t:string, l:EventListener, cap?: boolean) => void; - removeEventListener: (t:string, l:EventListener, cap?: boolean) => void; - dispatchEvent(e:_Event): boolean { - return true; - } -} - -// https://github.com/slightlyoff/DOMPromise/blob/master/DOMPromise.idl -class Resolver { - public accept(v:any): void {} - public reject(v:any): void {} - public resolve(v:any): void {} -} - -class Promise { - // Callback type decl: - // callback : (n : number) => number - constructor(init : (r:Resolver) => void ) { - - } - - // Not entirely sure what I'm doing here, just trying to keep - // typescript happy - then(fulfilled : (val:any) => any) : Promise; - then(fulfilled : (val:any) => any, rejected : (val:any) => any) : Promise; - then(fulfilled:any) : Promise { - return accepted(); - } - - catch(rejected : (val:any) => any) : Promise { - return accepted(); - } - - static all(...stuff:any[]) : Promise { - return accepted(); - } - - static resolve(val?:any) { - return new Promise(function(r) { - r.accept(val); - }); - } - - static reject(err?:any) { - return new Promise(function(r) { - r.reject(err); - }); - } -} - -function accepted(v: any = true) : Promise { - return new Promise(function(r) { - r.accept(true); - }); -} - -function acceptedResponse() : Promise { - return new Promise(function(r) { - r.accept(new Response()); - }); -} - -function fetch(url:any) : Promise { - return acceptedResponse(); -} - -interface ConnectEventHandler { (e:_Event); } - -// http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#shared-workers-and-the-sharedworker-interface -class SharedWorker extends _EventTarget { - // To make it clear where onconnec31t comes from - onconnect: ConnectEventHandler; - - constructor(url: string, name?: string) { - super(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Not part of any public standard but used above: -//////////////////////////////////////////////////////////////////////////////// - -var _useWorkerResponse = function() : Promise { return accepted(); }; -var _defaultToBrowserHTTP = function(url?) : Promise { return accepted(); }; - -function _castToRequest(request:any): Request { - if (!(request instanceof Request)) { - request = new Request({ - 'url': new _URL(request/*, this script url */).href - }); - } - return request; -} diff --git a/spec/assets/scripts/capture.js b/spec/assets/scripts/capture.js new file mode 100644 index 00000000..f7b36790 --- /dev/null +++ b/spec/assets/scripts/capture.js @@ -0,0 +1,620 @@ +(function() { + "use strict"; + + function capture(window) { + // Todo: Support other browsers + // Firefox currently has a different post-webcomponent-markup structure + if(navigator.userAgent.indexOf("Chrome") != -1 ) { + ; + } else { + alert("Capture is yet to be supported in this browser."); + return; + } + + var snapshot = new Snapshot(window); + + snapshot.replaceSpecSection(); + snapshot.replaceSpecClause(); + snapshot.replaceSpecAlgorithm(); + snapshot.replaceCode(); + snapshot.replaceIDL(); + snapshot.setSectionNumber(); + snapshot.setSectionAnchor(); + snapshot.replaceSpecToc(); + snapshot.replaceHeader(); + + snapshot.download(); + } + + function Snapshot(window) { + this.document = window.document.cloneNode(true); + }; + + Snapshot.prototype.replaceSpecSection = function() { + var specClauses = this.document.querySelectorAll("spec-clause"); + + for (var i = 0, n = specClauses.length; i < n; ++i) { + var specSections = specClauses[i].querySelectorAll("spec-section"); + + for (var j = 0, m = specSections.length; j < m; ++j) { + var section = this.document.createElement("section"); + section.innerHTML = '
{{sec_num}}
'; + + var sectionID = specSections[j].getAttribute("id"); + var header = specSections[j].querySelector("h1"); + var node = header.cloneNode(true); + + var contents = []; + var firstChild = specSections[j].firstChild; + while (firstChild) { + if (firstChild.nodeName != "H1") { + if (firstChild.nodeName == "P") { + firstChild.removeAttribute("para_num"); + } + contents.push(firstChild); + } + firstChild = firstChild.nextSibling; + } + + specSections[j].parentNode.replaceChild(section, specSections[j]); + section.setAttribute("title", sectionID); + var targetContents = section.querySelectorAll("content"); + targetContents[0].parentNode.replaceChild(node, targetContents[0]); + + contents.forEach(function(content) { + targetContents[1].parentNode.appendChild(content); + }); + targetContents[1].parentNode.removeChild(targetContents[1]); + } + } + }; + + Snapshot.prototype.replaceSpecClause = function() { + var specClauses = this.document.querySelectorAll("spec-clause"); + + for (var i = 0, n = specClauses.length; i < n; ++i) { + var section = this.document.createElement("section"); + section.innerHTML = '
{{sec_num}}
'; + + var sectionID = specClauses[i].getAttribute("id"); + var header = specClauses[i].querySelector("h1"); + var node = header.cloneNode(true); + + var contents = []; + var firstChild = specClauses[i].firstChild; + while (firstChild) { + if (firstChild.nodeName != "H1") { + if (firstChild.nodeName == "P") { + firstChild.removeAttribute("para_num"); + } + contents.push(firstChild); + } + firstChild = firstChild.nextSibling; + } + + specClauses[i].parentNode.replaceChild(section, specClauses[i]); + section.setAttribute("title", sectionID); + var targetContents = section.querySelectorAll("content"); + targetContents[0].parentNode.replaceChild(node, targetContents[0]); + + contents.forEach(function(content) { + targetContents[1].parentNode.appendChild(content); + }); + targetContents[1].parentNode.removeChild(targetContents[1]); + } + }; + + Snapshot.prototype.replaceSpecAlgorithm = function() { + var specAlgorithms = this.document.querySelectorAll("spec-algorithm"); + + for (var i = 0, n = specAlgorithms.length; i < n; ++i) { + var div = this.document.createElement("div"); + div.innerHTML = ''; + div.setAttribute("class", "algorithm"); + + var contents = []; + var firstChild = specAlgorithms[i].firstChild; + while (firstChild) { + contents.push(firstChild); + firstChild = firstChild.nextSibling; + } + + specAlgorithms[i].parentNode.replaceChild(div, specAlgorithms[i]); + var targetContent = div.querySelector("content"); + + contents.forEach(function(content) { + targetContent.parentNode.appendChild(content); + }); + targetContent.parentNode.removeChild(targetContent); + } + }; + + Snapshot.prototype.replaceCode = function() { + var specCodes = this.document.querySelectorAll("spec-code"); + + for (var i = 0, n = specCodes.length; i < n; ++i) { + var pre = this.document.createElement("pre"); + pre.innerHTML = ''; + + var contents = []; + var firstChild = specCodes[i].firstChild; + while (firstChild) { + contents.push(firstChild); + firstChild = firstChild.nextSibling; + } + + specCodes[i].parentNode.replaceChild(pre, specCodes[i]); + var targetContent = pre.querySelector("content"); + + contents.forEach(function(content) { + targetContent.parentNode.appendChild(content); + }); + targetContent.parentNode.removeChild(targetContent); + } + }; + + Snapshot.prototype.replaceIDL = function() { + var specIDL = this.document.querySelectorAll("spec-idl"); + + for (var i = 0, n = specIDL.length; i < n; ++i) { + var pre = this.document.createElement("pre"); + pre.innerHTML = ''; + + var contents = []; + var firstChild = specIDL[i].firstChild; + while (firstChild) { + contents.push(firstChild); + firstChild = firstChild.nextSibling; + } + + specIDL[i].parentNode.replaceChild(pre, specIDL[i]); + var targetContent = pre.querySelector("content"); + + contents.forEach(function(content) { + targetContent.parentNode.appendChild(content); + }); + targetContent.parentNode.removeChild(targetContent); + } + }; + + Snapshot.prototype.setSectionNumber = function() { + var sections = this.document.querySelectorAll("section"); + + for (var i = 0, n = sections.length; i < n; ++i) { + var header = sections[i].querySelector("header"); + var span = header.querySelector("span"); + var h1 = header.querySelector("h1"); + var secNum = h1.getAttribute("data-bookmark-label"); + if (secNum != null) { + span.textContent = secNum.substr(0, secNum.indexOf(' ')); + + // Replace section's h1 elements with right levels of h elements + var re = /\./g; + var dot = span.textContent.match(re); + var h, n; + + if (dot == null) + h = this.document.createElement("h2"); + else if (dot.length == 1) + h = this.document.createElement("h3"); + else if (dot.length == 2) + h = this.document.createElement("h4"); + + h.setAttribute("id", sections[i].title); + h.setAttribute("data-bookmark-label", h1.getAttribute("data-bookmark-label")); + h.innerHTML = h1.innerHTML; + h1.parentNode.replaceChild(h, h1); + + } else { // fixme: data-bookmark-label is not set for this element + if (h1.innerHTML == "Cross-Origin Resources and CORS") { + span.textContent = "6.2"; + h = this.document.createElement("h3"); + h.setAttribute("id", sections[i].title); + h.innerHTML = h1.innerHTML; + h1.parentNode.replaceChild(h, h1); + } + } + } + }; + + Snapshot.prototype.setSectionAnchor = function() { + var sections = this.document.querySelectorAll("section"); + + for (var i = 0, n = sections.length; i < n; ++i) { + var a = sections[i].querySelector("a"); + var id = sections[i].getAttribute("title"); + a.setAttribute("href", "#" + id); + } + }; + + Snapshot.prototype.replaceSpecToc = function() { + var specToc = this.document.querySelector("spec-toc"); + var sections = this.document.querySelectorAll("section"); + + var nav = this.document.createElement("nav"); + var h2 = this.document.createElement("h2"); + h2.setAttribute("id", "toc"); + h2.innerHTML = "Table of Contents"; + var ol = this.document.createElement("ol"); + nav.appendChild(h2); + nav.appendChild(ol); + + var lastNode = ol; + var lastHierarchy = "section"; + var hierarchy = "section"; + + for (var i = 0, n = sections.length; i < n; ++i) { + var sectionID = sections[i].getAttribute("title"); + var secNum = sections[i].querySelector("span").innerHTML; + var secTitle = sections[i].querySelector("h2, h3, h4"); + + if (secTitle.firstChild.nodeName == "CODE") + secTitle = secTitle.firstChild.innerHTML; + else + secTitle = secTitle.innerHTML; + + var li = this.document.createElement("li"); + var span = this.document.createElement("span"); + span.setAttribute("class", "marker"); + span.innerHTML = secNum + " "; + var a = this.document.createElement("a"); + a.setAttribute("href", "#" + sectionID); + a.innerHTML = secTitle; + li.appendChild(span); + li.appendChild(a); + + + var re = /\./g; + var dot = secNum.match(re); + + if (dot == null) hierarchy = "section"; + else if (dot.length == 1) hierarchy = "subsection"; + else if (dot.length == 2) hierarchy = "subsubsection"; + + if (lastHierarchy == "section") { + if (hierarchy == "section") { + ol.appendChild(li); + } else if (hierarchy == "subsection") { + var subOl = this.document.createElement("ol"); + subOl.appendChild(li); + lastNode.appendChild(subOl); + } + } else if (lastHierarchy == "subsection") { + if (hierarchy == "section") { + ol.appendChild(li); + } else if (hierarchy == "subsection") { + lastNode.parentNode.appendChild(li); + } else if (hierarchy == "subsubsection") { + var subsubOl = this.document.createElement("ol"); + subsubOl.appendChild(li); + lastNode.appendChild(subsubOl); + } + } else if (lastHierarchy == "subsubsection") { + if (hierarchy == "section") { + ol.appendChild(li); + } else if (hierarchy == "subsection") { + lastNode.parentNode.parentNode.parentNode.appendChild(li); + } else if (hierarchy == "subsubsection") { + lastNode.parentNode.appendChild(li); + } + } + + lastNode = li; + lastHierarchy = hierarchy; + } + + specToc.parentNode.replaceChild(nav, specToc); + }; + + Snapshot.prototype.replaceHeader = function() { + var head = this.document.querySelector("head"); + var scripts = head.querySelectorAll("script"); + + for (var i = 0, n = scripts.length; i < n; ++i) { + scripts[i].parentNode.removeChild(scripts[i]); + } + + var captureButton = this.document.querySelector("#capture-button"); + captureButton.parentNode.removeChild(captureButton); + + var styles = head.querySelectorAll("style"); + + for (var i = 0, n = styles.length; i < n; ++i) { + styles[i].parentNode.removeChild(styles[i]); + } + + var style = this.document.createElement("style"); + style.innerHTML = mainStyle; + + var meta = head.querySelector("meta"); + meta.nextSibling.parentNode.insertBefore(style, meta.nextSibling); + + var w3css = this.document.createElement("link"); + w3css.setAttribute("rel", "stylesheet"); + w3css.setAttribute("href", "https://www.w3.org/StyleSheets/TR/W3C-ED"); + w3css.setAttribute("type", "text/css"); + + var link = head.querySelector("link"); + link.parentNode.replaceChild(w3css, link); + }; + + Snapshot.prototype.download = function() { + var x = window.open(); + var a = x.document.createElement("a"); + a.text = "Document captured. Download!"; + a.setAttribute("href", "data:text/html;charset=utf-8," + encodeURIComponent("\n" + this.document.querySelector("html").outerHTML)); + a.setAttribute("download", "serviceworker-snapshot.html"); + x.document.body.appendChild(a); + x.document.close(); + }; + + document.addEventListener('DOMContentLoaded', function() { + document.querySelector("#capture-button") + .addEventListener("click", function() { capture(self); }); + }); + + var mainStyle = "body {\n" + + "/* padding: 2em 1em 2em 70px;\n" + + " margin: 0; */\n" + + " color: black;\n" + + " background: white;\n" + + " background-position: top left;\n" + + " background-attachment: fixed;\n" + + " background-repeat: no-repeat;\n" + + "\n" + + "/* line-height: 1.5em;*/\n" + + "}\n" + + "\n" + + ".logo > a {\n" + + " border-bottom: none;\n" + + "}\n" + + "\n" + + "article, aside, footer, header, hgroup, main, nav, section {\n" + + " display: block;\n" + + "}\n" + + "\n" + + "header {\n" + + " font-weight: bold;\n" + + " margin-top: 20px;\n" + + " margin-bottom: 20px;\n" + + "}\n" + + "\n" + + "header::after {\n" + + "clear: both;\n" + + "display: block;\n" + + "content: \" \";\n" + + "height: 0;\n" + + "}\n" + + "\n" + + "section > header > h1, section > header > h2, section > header > h3, section > header > h4, section > header > h5 {\n" + + " display: inline;\n" + + " font-size: 100%;\n" + + " font-weight: bold;\n" + + "}\n" + + "\n" + + "body > pre.prettyprint,\n" + + "body > section pre {\n" + + " background-color: #eee;\n" + + " padding: 0 2em 1em 2em;\n" + + " margin: 0;\n" + + " border: none;\n" + + "}\n" + + "\n" + + "header > ul {\n" + + " font-size: 0.8em;\n" + + " list-style: none;\n" + + " margin: 0 -1em;\n" + + " padding: 0.3em 0;\n" + + " background-color: #eee;\n" + + "}\n" + + "\n" + + "header > ul > li {\n" + + " display: inline;\n" + + " margin: 0 0 0 1em;\n" + + "}\n" + + "\n" + + "header > ul > li:nth-of-type(3) {\n" + + " display: inline;\n" + + " margin: 0 0 0 5em;\n" + + "}\n" + + "\n" + + "var {\n" + + " color: #005A9C;\n" + + " font-style: normal;\n" + + "}\n" + + "\n" + + ".section-number, .anchor > a {\n" + + "color: #005A9C;\n" + + "}\n" + + "\n" + + ".anchor {\n" + + "padding-right: 1em;\n" + + "font-size: 0.8em;\n" + + "float: right;\n" + + "text-decoration: none;\n" + + "}\n" + + "\n" + + ".fixme {\n" + + " display: block;\n" + + " padding: 10px 0 0 20px;\n" + + " border-left: 5px solid #E05252;\n" + + "}\n" + + "\n" + + "\n" + + ".fixme:before {\n" + + " content: 'To be addressed';\n" + + " float: right;\n" + + " display: block;\n" + + " padding: 2px 10px;\n" + + " background-image: -webkit-linear-gradient(top left, #FFFFFF 0%, #FBE9E9 100%);\n" + + " background-image: linear-gradient(to bottom right, #FFFFFF 0%, #FBE9E9 100%);\n" + + " font-size: 0.9em;\n" + + "}\n" + + "\n" + + ".note {\n" + + " color: green;\n" + + " font-weight: bold;\n" + + " font-style: italic;\n" + + " padding-left: 2em;\n" + + "}\n" + + "\n" + + ".note:before {\n" + + " content: \"Note: \";\n" + + "}\n" + + "\n" + + ".warning:before {\n" + + " content: \"WARNING: \";\n" + + " font-weight: bold;\n" + + "}\n" + + "\n" + + ".warning {\n" + + " padding: 10px 10px;\n" + + " width: 100%;\n" + + " background: #fffaba;\n" + + " box-sizing: border-box;\n" + + "}\n" + + "\n" + + "dfn {\n" + + " font-style: normal;\n" + + " font-weight: bold;\n" + + " background-color: #f9f9f9;\n" + + " padding: 0 2px;\n" + + " outline: 1px solid #eee;\n" + + "}\n" + + "\n" + + "dfn > code {\n" + + " background-color: transparent;\n" + + "}\n" + + "\n" + + "dfn.no-references {\n" + + " background-color: #ffefef;\n" + + "}\n" + + "\n" + + "dfn:target, a:target {\n" + + " background-color: #FFFF91;\n" + + "}\n" + + "\n" + + "a[href*=dfn-] {\n" + + " border-bottom: 1px dotted #ccc;\n" + + "}\n" + + "\n" + + "div.informative:before {\n" + + " content: 'Informative';\n" + + " float: right;\n" + + " display: block;\n" + + " padding: 2px 10px;\n" + + " background-image: -webkit-linear-gradient(top left, #FFFFFF 0%, #D3EEDF 100%);\n" + + " background-image: linear-gradient(to bottom right, #FFFFFF 0%, #D3EEDF 100%);\n" + + " font-size: 0.9em;\n" + + "}\n" + + "\n" + + "div.informative {\n" + + " padding: 10px 0 0 20px;\n" + + " border-left: 5px solid #D3EEDF;\n" + + "}\n" + + "\n" + + "div.monkeypatch:before {\n" + + " content: 'Monkeypatch';\n" + + " float: right;\n" + + " display: block;\n" + + " padding: 2px 10px;\n" + + " background-image: -webkit-linear-gradient(top left, #FFFFFF 0%, #D3EEDF 100%);\n" + + " background-image: linear-gradient(to bottom right, #FFFFFF 0%, #D3EEDF 100%);\n" + + " font-size: 0.9em;\n" + + "}\n" + + "\n" + + "div.monkeypatch {\n" + + " padding: 10px 0 0 20px;\n" + + " border-left: 5px solid #EEE5D3;\n" + + "}\n" + + "\n" + + "div.deprecated:before {\n" + + " content: 'Deprecated parts';\n" + + " float: right;\n" + + " display: block;\n" + + " padding: 2px 10px;\n" + + " background-image: -webkit-linear-gradient(top left, #FFFFFF 0%, #fffaba 100%);\n" + + " background-image: linear-gradient(to bottom right, #FFFFFF 0%, #fffaba 100%);\n" + + " font-size: 0.9em;\n" + + "}\n" + + "\n" + + "div.deprecated {\n" + + " opacity: 0.6;\n" + + "}\n" + + "\n" + + "table {\n" + + " border: 1px solid #ccc;\n" + + "}\n" + + "table code {\n" + + " background-color: transparent;\n" + + "}\n" + + "td, th {\n" + + " padding: 0.5em;\n" + + " vertical-align: top;\n" + + "}\n" + + "td {\n" + + " border-bottom: 1px solid #ddd;\n" + + "}\n" + + "tr:last-of-type td {\n" + + " border-bottom: none;\n" + + "}\n" + + "th {\n" + + " text-align: left;\n" + + " background-color: #eee;\n" + + "}\n" + + "/*\n" + + "dt, dd {\n" + + " margin-top: 0;\n" + + " margin-bottom: 0;\n" + + "}\n" + + "dt {\n" + + " font-weight: bold;\n" + + "}\n" + + "dd {\n" + + " padding-bottom: 7px;\n" + + "}\n" + + "*/\n" + + "div.algorithm {\n" + + " padding: 0 0 0 20px;\n" + + " border-left: 5px solid #EAF7F9;\n" + + "}\n" + + "pre {\n" + + " background-color: #eee;\n" + + " padding: 0.5em 1em 0.5em 1em;\n" + + " margin: 0;\n" + + " border: none;\n" + + "}\n" + + "code {\n" + + " background-color: #eee;\n" + + " font-family: 'Droid Sans Mono', monospace;\n" + + " font-size: 0.9em;\n" + + "}\n" + + "code > ins {\n" + + " background-color: #BBFFDF;\n" + + " text-decoration: none;\n" + + "}\n" + + "code > del {\n" + + " background-color: #FF979D;\n" + + "}\n" + + "nav > ol {\n" + + " font-size: 0.9em;\n" + + "}\n" + + "nav ol {\n" + + " font-weight: normal;\n" + + " padding-left:0;\n" + + " margin-left: 0;\n" + + "}\n" + + "\n" + + "/* Browsers don't support ::marker or display:marker, so emulate it. */\n" + + "nav li {\n" + + " list-style-type: none;\n" + + "}\n" + + "nav.marker { display: inline-block; }\n" + + "nav li .marker { width: 1em; text-align: left; }\n" + + "nav ol ol { margin-left: 1.75em; }\n" + + "nav li li .marker { width: 2em; }\n" + + "nav ol ol ol { margin-left: 2em; }\n" + + "nav li li li .marker { width: 3em; }\n" + + "nav ol ol ol ol { margin-left: 3em; }\n" + + "nav li li li li .marker { width: 3.25em; }\n"; +})(); diff --git a/spec/assets/web-spec-framework b/spec/assets/web-spec-framework index 54b969a2..da5fc434 160000 --- a/spec/assets/web-spec-framework +++ b/spec/assets/web-spec-framework @@ -1 +1 @@ -Subproject commit 54b969a20abc88366947f63a875143ea99bb8c9d +Subproject commit da5fc434981fdf199d08029ca3abf731885a3eca diff --git a/spec/service_worker/index.bs b/spec/service_worker/index.bs new file mode 100644 index 00000000..30311096 --- /dev/null +++ b/spec/service_worker/index.bs @@ -0,0 +1,4334 @@ + + +
+{
+  "promises-guide": {
+    "href": "https://www.w3.org/2001/tag/doc/promises-guide",
+    "title": "Writing Promise-Using Specifications",
+    "date": "24 July 2015",
+    "status": "Finding of the W3C TAG",
+    "publisher": "W3C TAG"
+  },
+  "unsanctioned-tracking": {
+    "href": "https://www.w3.org/2001/tag/doc/unsanctioned-tracking",
+    "title": "Unsanctioned Web Tracking",
+    "date": "17 July 2015",
+    "status": "Finding of the W3C TAG",
+    "publisher": "W3C TAG"
+  }
+}
+
+ + + +
+spec: dom-ls; urlPrefix: https://dom.spec.whatwg.org/
+    type: dfn; text: ASCII case-insensitive; url: ascii-case-insensitive
+
+spec: ecma-262; urlPrefix: http://www.ecma-international.org/ecma-262/6.0/
+    type: dfn
+        text: Assert; url: sec-algorithm-conventions
+        text: [[Call]]; url: sec-ecmascript-function-objects-call-thisargument-argumentslist
+        text: map objects; url: sec-map-objects
+        text: promise; url: sec-promise-objects
+        url: sec-list-and-record-specification-type
+            text: List
+            text: Record
+
+spec: csp2; urlPrefix: https://w3c.github.io/webappsec-csp/2/
+    type: dfn
+        text: enforce
+        text: monitor
+
+spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
+    type: dfn
+        text: basic filtered response; url: concept-filtered-response-basic
+        text: CORS filtered response; url: concept-filtered-response-cors
+        text: disturbed; url: concept-body-disturbed
+        text: empty; url: concept-empty-readablestream
+        text: extract a mime type; url: concept-header-extract-mime-type
+        text: fetch; url: concept-fetch
+        text: filtered response; url: concept-filtered-response
+        text: get a reader; url: concept-get-reader
+        text: header; url: concept-header
+        text: http fetch; url: concept-http-fetch
+        text: internal response; url: concept-internal-response
+        text: locked; url: concept-body-locked
+        text: navigation request
+        text: network error; url: concept-network-error
+        text: non-subresource request
+        text: ok status; url: ok-status
+        text: opaque filtered response; url: concept-filtered-response-opaque
+        text: opaque-redirect filtered response; url: concept-filtered-response-opaque-redirect
+        text: potential-navigation-or-subresource request
+        text: process response
+        text: process response end-of-file
+        text: read all bytes; url: concept-read-all-bytes-from-readablestream
+        text: ReadableStream; url: concept-readablestream
+        text: request; for: fetch; url: concept-request
+        text: response; for: fetch; url: concept-response
+        text: skip service worker flag
+        text: stream; url: concept-body-stream
+        text: subresource request
+        text: synchronous flag
+        text: terminate; url: concept-fetch-terminate
+        text: guard; for: headers; url: concept-headers-guard
+        for: header; urlPrefix: #concept-header-
+            text: name
+            text: parsing; url: parse
+        for: request; urlPrefix: #concept-request-
+            text: cache mode
+            text: client
+            text: destination
+            text: header list
+            text: initiator
+            text: method
+            text: origin
+            text: redirect mode
+            text: request
+            text: url
+        for: response; urlPrefix: #concept-response-
+            text: body
+            text: cache state
+            text: CORS-exposed header-names list
+            text: header list
+            text: response
+            text: status
+            text: termination reason
+            text: type
+    type: interface
+        text: Headers
+        text: Request
+        text: RequestInfo
+        text: Response
+    type: attribute; for: Request
+        text: headers; url: dom-request-headers
+    type: method
+        text: get(name); for: Headers; url: dom-headers-get
+        text: fetch(input, init); for: GlobalFetch; url: dom-global-fetch
+
+spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
+    type: dfn
+        urlPrefix: browsers.html
+            text: origin; for: resource; url: origin-2
+        urlPrefix: infrastructure.html
+            text: read only array; url: dfn-read-only-array
+        urlPrefix: interaction.html
+            text: has focus steps
+        urlPrefix: webappapis.html
+            text: classic script
+            text: creation url
+            text: dom manipulation task source
+            text: fetch a classic worker script
+            text: fetch a module script tree
+            text: fire a simple event
+            text: https state
+            text: module script
+            text: realm execution context
+            text: report the error
+            text: run a classic script
+            text: run a module script
+            text: script; url: concept-script
+            text: set up the request; url: fetching-scripts-set-up-request
+            text: task queue; for: event loop
+            text: validate the response; url: fetching-scripts-validate-response
+        urlPrefix: workers.html
+            text: get a fetch result
+            text: https state
+            text: import scripts into worker global scope
+            text: kill a worker
+            text: postprocess the fetch result
+            text: runtime script errors handling; url: runtime-script-errors-2
+            text: shared workers
+            text: terminate a worker
+            text: validate the state
+            text: web worker; url: workers
+            for: workerglobalscope; urlPrefix: #concept-workerglobalscope-
+                text: https state
+                text: type
+                text: url
+    type: event
+        urlPrefix: indices.html
+            text: DOMContentLoaded; for: Document; url: event-domcontentloaded
+            text: message; for: Window; url: event-message
+
+spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/
+    type: enum; text: VisibilityState; url: VisibilityState
+    type: attribute; text: visibilityState; for: Document; url: dom-document-visibilitystate
+
+spec: powerful-features; urlPrefix: https://w3c.github.io/webappsec/specs/powerfulfeatures/#
+    type: dfn
+        text: is origin potentially trustworthy; url: is-origin-trustworthy
+        text: risks associated with insecure contexts; url: threat-risks
+        text: secure context
+
+spec: promises-guide; urlPrefix: https://www.w3.org/2001/tag/doc/promises-guide#
+    type: dfn
+        text: waiting for all
+        text: transforming; url: transforming-by
+
+spec: quota-api; urlPrefix: http://www.w3.org/TR/quota-api/
+    type: attribute; for: ServiceWorkerGlobalScope
+        text: onbeforeevicted; url: widl-ServiceWorkerGlobalScope-onbeforeevicted
+        text: onevicted; url: widl-ServiceWorkerGlobalScope-onevicted
+
+spec: rfc7230; urlPrefix: https://tools.ietf.org/html/rfc7230
+    type: dfn
+        text: field-value; for: http; url: section-3.2
+
+spec: rfc7231; urlPrefix: https://tools.ietf.org/html/rfc7231
+    type: dfn
+        text: Vary; url: section-7.1.4
+
+spec: url; urlPrefix: https://url.spec.whatwg.org/
+    type: dfn
+        text: parsing; for: url; url: concept-url-parser
+        text: serialized; for: url; url: concept-url-serializer
+
+spec: webidl; urlPrefix: https://heycam.github.io/webidl/
+    type: dfn
+        text: throw; url: dfn-throw
+    type: exception
+        text: DataCloneError
+        text: InvalidAccessError
+        text: InvalidStateError
+        text: NetworkError
+        text: NotFoundError
+        text: QuotaExceededError
+        text: SecurityError
+
+ +
+

Motivations

+ + This section is non-normative. + +

Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

+ +

The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

+ +

Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

+ +

Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

+ +

Service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

+ +

Service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

+
+ +
+

Model

+ +
+

Service Worker

+ +

A service worker is a type of web worker. A service worker executes in the registering service worker client's origin.

+

A service worker has an associated state, which is one of parsed, installing, installed, activating, activated, and redundant. It is initially parsed.

+

A service worker has an associated script url (a URL).

+

A service worker has an associated type which is either "classic" or "module". Unless stated otherwise, it is "classic".

+

A service worker has an associated containing service worker registration (a service worker registration), which contains itself.

+

A service worker has an associated id (an opaque string), which uniquely identifies itself during the lifetime of its containing service worker registration.

+

A service worker is dispatched a set of lifecycle events, install and activate, and functional events including fetch.

+

A service worker has an associated script resource (a script), which represents its own script resource. It is initially set to null. A script resource has an associated has ever been evaluated flag. It is initially unset. A script resource has an associated HTTPS state which is "none", "deprecated", or "modern". Unless stated otherwise, it is "none".

+

A service worker has an associated script resource map which is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a URL and \[[value]] is a script resource.

+

A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.

+

A service worker has an associated imported scripts updated flag. It is initially unset.

+

A service worker has an associated set of event types to handle whose element type is an event listener's event type. It is initially set to null.

+

A service worker has an associated list of foreign fetch scopes whose element type is a URL. It is initially empty.

+

A service worker has an associated list of foreign fetch origins whose element type is a URL. It is initially empty.

+ +
+

Lifetime

+ +

The lifetime of a service worker is tied to the execution lifetime of events and not references held by service worker clients to the ServiceWorker object.

+

A user agent may terminate service workers at any time it:

+
    +
  • Has no event to handle.
  • +
  • Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events.
  • +
+
+
+ +
+

Service Worker Registration

+ +

A service worker registration is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. A user agent may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

+

A service worker registration has an associated scope url (a URL).

+

A service worker registration has an associated registering script url (a URL).

+

A service worker registration has an associated installing worker (a service worker) whose state is installing. It is initially set to null.

+

A service worker registration has an associated waiting worker (a service worker) whose state is installed. It is initially set to null.

+

A service worker registration has an associated active worker (a service worker) whose state is either activating or activated. It is initially set to null.

+

A service worker registration has an associated last update check time. It is initially set to null.

+

A service worker registration has an associated uninstalling flag. It is initially unset.

+

A service worker registration has one or more task queues that back up the tasks from its active worker's event loop's corresponding task queues. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker's tasks to the service worker registration's task queues when the active worker is terminated and re-queues those tasks to the active worker's event loop's corresponding task queues when the active worker spins off. Unlike the task queues owned by event loops, the service worker registration's task queues are not processed by any event loops in and of itself.

+ +
+

Lifetime

+ +

A user agent must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of service worker registration's scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

+
+
+ +
+

Service Worker Client

+

A service worker client is an environment settings object that specifies various settings for its JavaScript global environment.

+ +

A service worker client has an associated active worker (an active worker) which currently controls it. It is initially set to null.

+ +

A service worker client has an associated id (an opaque string), which uniquely identifies itself during its lifetime. It is initially set to a new unique value when the corresponding environment settings object that it represents is created.

+ +

A service worker client has an associated frame type, which is one of auxiliary, top-level, nested, and none. Unless stated otherwise it is none. + +

A window client is a service worker client whose global object is a {{Window}} object.

+ +

A dedicated worker client is a service worker client whose global object is a {{DedicatedWorkerGlobalScope}} object.

+ +

A shared worker client is a service worker client whose global object is a {{SharedWorkerGlobalScope}} object.

+ +

A worker client is either a dedicated worker client or a shared worker client.

+
+ +
+

Selection and Use

+ +

A service worker client independently selects and uses a service worker registration for its own loading and its subresources. The selection of a service worker registration, upon a non-subresource request, is a process of either matching a service worker registration from scope to registration map or inheriting an existing service worker registration from its parent or owner context depending on the request's url.

+ +

When the request's url is not local, a service worker client matches a service worker registration from scope to registration map. That is, the service worker client attempts to consult a service worker registration whose scope url matches its creation url.

+ +

When the request's url is local, if the service worker client's responsible browsing context is a nested browsing context or the service worker client is a worker client, the service worker client inherits the service worker registration from its parent browsing context's environment or one of the worker's Documents' environment, respectively, if it exists.

+ +

If the selection was successful, the selected service worker registration's active worker starts to control the service worker client. Otherwise, the flow returns to fetch where it falls back to the default behavior. When a service worker client is controlled by an active worker, it is considered that the service worker client is using the active worker's containing service worker registration.

+
+ +
+

Task Sources

+ +

The following additional task sources are used by service workers.

+ +
+
The handle fetch task source
+
This task source is used for dispatching fetch events to service workers.
+
The handle functional event task source
+
This task source is used for features that dispatch other functional events, e.g. push events, to service workers. +

A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. For instance, a user agent may use a different task source for task events from other task sources.

+
+
+
+ +
+

User Agent Shutdown

+ +

A user agent must maintain the state of its stored service worker registrations across restarts with the following rules: +

+

+ +

To attain this, the user agent must invoke Handle User Agent Shutdown when it terminates.

+
+
+ +
+

Client Context

+ +
+ Bootstrapping with a ServiceWorker: + +
+      // scope defaults to the path the script sits in
+      // "/" in this example
+      navigator.serviceWorker.register("/serviceworker.js").then(
+        function(registration) {
+          console.log("success!");
+          if (registration.installing) {
+            registration.installing.postMessage("Howdy from your installing page.");
+          }
+        },
+        function(why) {
+          console.error("Installing the worker failed!:", why);
+        });
+    
+
+ +
+

{{ServiceWorker}}

+ +
+      [Exposed=(Window,Worker)]
+      interface ServiceWorker : EventTarget {
+        readonly attribute USVString scriptURL;
+        readonly attribute ServiceWorkerState state;
+        void postMessage(any message, optional sequence<Transferable> transfer);
+
+        // event
+        attribute EventHandler onstatechange;
+      };
+      ServiceWorker implements AbstractWorker;
+
+      enum ServiceWorkerState {
+        "installing",
+        "installed",
+        "activating",
+        "activated",
+        "redundant"
+      };
+    
+ +

A ServiceWorker object represents a service worker. Each {{ServiceWorker}} object is associated with a service worker. Multiple separate objects implementing the {{ServiceWorker}} interface across document environments and worker environments can all be associated with the same service worker simultaneously.

+ +

A {{ServiceWorker}} object has an associated {{ServiceWorkerState}} object which is itself associated with service worker's state.

+ +
+

{{ServiceWorker/scriptURL}}

+ +

The scriptURL attribute must return the service worker's serialized script url.

+ +
+

For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

+ +
+          // Script on the page https://example.com/app.html
+          navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
+        
+ +

The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

+
+
+ +
+

{{ServiceWorker/state}}

+ +

The state attribute must return the value (in ServiceWorkerState enumeration) corresponding to the first matching statement, switching on the service worker's state:

+ +
+
installing
+
"installing" +

The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

+ +
installed
+
"installed" +

The service worker in this state is considered a waiting worker.

+ +
activating
+
"activating" +

The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

+ +
activated
+
"activated" +

The service worker in this state is considered an active worker ready to handle functional events.

+ +
redundant
+
"redundant" +

A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

+
+
+ +
+

{{ServiceWorker/postMessage(message, transfer)}}

+ +

The postMessage(message, transfer) method must run these steps or their equivalent:

+ +
    +
  1. If the {{ServiceWorker/state}} attribute value of the context object is "redundant", throw an "{{InvalidStateError}}" exception and abort these steps.
  2. +
  3. Let newPorts be an empty array.
  4. +
  5. Let transferMap be an empty association list of {{Transferable}} objects to placeholder objects.
  6. +
  7. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. If any object is listed in transfer more than once, or any of the {{Transferable}} objects listed in transfer are marked as neutered, then throw a "{{DataCloneError}}" exception and abort these steps.
    2. +
    3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a {{MessagePort}} object, also append the placeholder object to newPorts.
    4. +
    +
  8. +
  9. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
  10. +
  11. Let serviceWorker be the service worker represented by the context object.
  12. +
  13. Invoke Run Service Worker algorithm with serviceWorker as the argument.
  14. +
  15. Let destination be the {{ServiceWorkerGlobalScope}} object associated with serviceWorker.
  16. +
  17. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. Let newOwner be the destination's environment settings object.
    2. +
    3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
    4. +
    +
  18. +
  19. Make newPorts into a read only array.
  20. +
  21. Queue a task that runs the following steps: +
      +
    1. Create an event e that uses the {{ExtendableMessageEvent}} interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Let the {{ExtendableMessageEvent/data}} attribute of e be initialized to clonedMessage.
    4. +
    5. Let the {{ExtendableMessageEvent/origin}} attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
    6. +
    7. If the global object globalObject specified by the incumbent settings object is a {{ServiceWorkerGlobalScope}} object, let the {{ExtendableMessageEvent/source}} attribute of e be initialized to a new {{ServiceWorker}} object that represents globalObject's service worker.
    8. +
    9. Else if globalObject is a {{Window}} object, let the {{ExtendableMessageEvent/source}} attribute of e be initialized to a new {{WindowClient}} object that represents globalObject's browsing context.
    10. +
    11. Else, let it be initialized to a new {{Client}} object that represents globalObject's worker environment.
    12. +
    13. Let the {{ExtendableMessageEvent/ports}} attribute of e be initialized to newPorts.
    14. +
    15. Dispatch e at destination.
    16. +
    +

    The task must use the DOM manipulation task source.

    +
  22. +
+
+ +
+

Event handler

+ +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorker}} interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onstatechangestatechange
+
+
+ +
+

{{ServiceWorkerRegistration}}

+ +
+      [Exposed=(Window,Worker)]
+      interface ServiceWorkerRegistration : EventTarget {
+        [Unforgeable] readonly attribute ServiceWorker? installing;
+        [Unforgeable] readonly attribute ServiceWorker? waiting;
+        [Unforgeable] readonly attribute ServiceWorker? active;
+
+        readonly attribute USVString scope;
+
+        [NewObject] Promise<void> update();
+        [NewObject] Promise<boolean> unregister();
+
+        // event
+        attribute EventHandler onupdatefound;
+      };
+    
+ +

A ServiceWorkerRegistration object represents a service worker registration. Each {{ServiceWorkerRegistration}} object is associated with a service worker registration (a service worker registration). Multiple separate objects implementing the {{ServiceWorkerRegistration}} interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

+ +
+ + +

installing attribute must return the result of running these steps or their equivalent:

+ +
    +
  1. Let installingWorker be the {{ServiceWorker}} object that represents the service worker registration's installing worker.
  2. +
  3. Return installingWorker.
  4. +
+ +

The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

+
+ +
+ + +

waiting attribute must return the result of running these steps or their equivalent:

+ +
    +
  1. Let waitingWorker be the {{ServiceWorker}} object that represents the service worker registration's waiting worker.
  2. +
  3. Return waitingWorker.
  4. +
+ +

The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

+
+ +
+ + +

active attribute must return the result of running these steps or their equivalent:

+ +
    +
  1. Let activeWorker be the {{ServiceWorker}} object that represents the service worker registration's active worker.
  2. +
  3. Return activeWorker.
  4. +
+ +

The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

+
+ +
+

{{ServiceWorkerRegistration/scope}}

+ +

The scope attribute must return service worker registration's serialized scope url.

+ +

In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

+
+ +
+

{{ServiceWorkerRegistration/update()}}

+ +

update() method must run these steps or their equivalent:

+ +
    +
  1. Let p be a promise.
  2. +
  3. Let registration be the service worker registration.
  4. +
  5. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
  6. +
  7. If newestWorker is null, reject p with an "{{InvalidStateError}}" exception and abort these steps.
  8. +
  9. If the context object's relevant settings object's global object globalObject is a {{ServiceWorkerGlobalScope}} object, and globalObject's associated service worker's state is installing, reject p with an "{{InvalidStateError}}" exception and abort these steps.
  10. +
  11. Let job be the result of running Create Job with update, registration's scope url, newestWorker's script url, p, and the context object's relevant settings object client.
  12. +
  13. Set job's worker type to newestWorker's type.
  14. +
  15. Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job.
    2. +
    +
  16. +
  17. Return p.
  18. +
+
+ +
+ + +

The {{ServiceWorkerRegistration/unregister()}} method unregisters the service worker registration. It is important to note that the currently controlled service worker client's active worker's containing service worker registration is effective until all the service worker clients (including itself) using this service worker registration unload. That is, the {{ServiceWorkerRegistration/unregister()}} method only affects subsequent navigations.

+ +

unregister() method must return the result of running these steps or their equivalent:

+ +
    +
  1. Let p be a promise.
  2. +
  3. Let job be the result of running Create Job with unregister, the scope url of the service worker registration, null, p, and the context object's relevant settings object client.
  4. +
  5. Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job.
    2. +
    +
  6. +
  7. Return p.
  8. +
+
+ +
+

Event handler

+ +

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

+ + + + + + + + + + + + + + +
event handlerevent handler event type
onupdatefoundupdatefound
+
+
+ +
+ + +
+      partial interface Navigator {
+        [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
+      };
+
+      partial interface WorkerNavigator {
+        [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
+      };
+    
+ +

The serviceWorker attribute must return the {{ServiceWorkerContainer}} object that is associated with the context object.

+
+ +
+

{{ServiceWorkerContainer}}

+ +
+      [Exposed=(Window,Worker)]
+      interface ServiceWorkerContainer : EventTarget {
+        [Unforgeable] readonly attribute ServiceWorker? controller;
+        [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
+
+        [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
+
+        [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
+        [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
+
+
+        // events
+        attribute EventHandler oncontrollerchange;
+        attribute EventHandler onerror;
+        attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
+      };
+    
+
+      dictionary RegistrationOptions {
+        USVString scope;
+        WorkerType type = "classic";
+      };
+    
+ +

The user agent must create a {{ServiceWorkerContainer}} object when a {{Navigator}} object or a {{WorkerNavigator}} object is created and associate it with that object.

+ +

A ServiceWorkerContainer provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

+ +

A {{ServiceWorkerContainer}} has an associated service worker client, which is a service worker client whose global object is associated with the {{Navigator}} object or the {{WorkerNavigator}} object that the {{ServiceWorkerContainer}} is retrieved from.

+ +

A {{ServiceWorkerContainer}} object has an associated ready promise (a promise). It is initially set to a new promise.

+ +
+ + +

controller attribute must return the result of running these steps or their equivalent:

+ +
    +
  1. Let client be the context object's service worker client.
  2. +
  3. If client is not a secure context, return undefined.
  4. +
  5. Return the {{ServiceWorker}} object that represents client's active worker.
  6. +
+ +

{{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} returns null if the request is a force refresh (shift+refresh). The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

+ +

The behavior of the attribute getter in non-secure contexts is in discussion.

+
+ +
+ + +

ready attribute must return the result of running these steps or their equivalent:

+ +
    +
  1. If the context object's ready promise is settled, return the context object's ready promise.
  2. +
  3. Let client be the context object's service worker client.
  4. +
  5. If client is not a secure context, return the context object's ready promise rejected with a "{{SecurityError}}" exception.
  6. +
  7. Let registration be null.
  8. +
  9. Let clientURL be client's creation url.
  10. +
  11. Run the following substeps in parallel: +
      +
    1. CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
        +
      1. Set registration to the result value.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Wait until scope to registration map has a new entry.
      2. +
      3. Jump to the step labeled CheckRegistration.
      4. +
      +
    4. +
    5. If registration's active worker is null, wait until registration's active worker changes. +

      Implementers should consider this condition is met when the corresponding registration request gets to the step 7 of Activate algorithm.

      +
    6. +
    7. Resolve context object's ready promise with the {{ServiceWorkerRegistration}} object which represents registration.
    8. +
    +
  12. +
  13. Return context object's ready promise.
  14. +
+ +

When the ready attribute is accessed in a secure context, the returned promise will never reject. Instead, it waits until the promise resolves with a service worker registration that has an active worker.

+
+ +
+ + +

The {{ServiceWorkerContainer/register(scriptURL, options)}} method creates or updates a service worker registration for the given scope url. If successful, a service worker registration ties the provided scriptURL to a scope url, which is subsequently used for navigation matching.

+ +

register(scriptURL, options) method must run these steps or their equivalent:

+ +
    +
  1. Let p be a promise.
  2. +
  3. Let client be the context object's service worker client.
  4. +
  5. If client is not a secure context, reject p with a "{{SecurityError}}" exception and abort these steps.
  6. +
  7. Let scriptURL be the result of parsing scriptURL with entry settings object's API base URL.
  8. +
  9. If scriptURL is failure, reject p with a TypeError and abort these steps.
  10. +
  11. If scriptURL's scheme is not one of "http" and "https", reject p with a TypeError and abort these steps.
  12. +
  13. If any of the strings in scriptURL's path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps.
  14. +
  15. Let scopeURL be null.
  16. +
  17. If options.{{RegistrationOptions/scope}} is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

    The scope url for the registration is set to the location of the service worker script by default.

    +
  18. +
  19. Else, set scopeURL to the result of parsing options.{{RegistrationOptions/scope}} with entry settings object's API base URL.
  20. +
  21. If scopeURL is failure, reject p with a TypeError and abort these steps.
  22. +
  23. If scopeURL's scheme is not one of "http" and "https", reject p with a TypeError and abort these steps.
  24. +
  25. If any of the strings in scopeURL's path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps.
  26. +
  27. Let job be the result of running Create Job with register, scopeURL, scriptURL, p, and client.
  28. +
  29. Set job's worker type to options.{{RegistrationOptions/type}}.
  30. +
  31. Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job.
    2. +
    +
  32. +
  33. Return p.
  34. +
+
+ +
+ + +

getRegistration(clientURL) method must run these steps or their equivalent:

+ +
    +
  1. Let client be the context object's service worker client.
  2. +
  3. If client is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  4. +
  5. Let clientURL be the result of parsing clientURL with entry settings object's API base URL.
  6. +
  7. If clientURL is failure, return a promise rejected with a TypeError.
  8. +
  9. If the origin of clientURL is not client's origin, return a promise rejected with a "{{SecurityError}}" exception.
  10. +
  11. Let promise be a new promise.
  12. +
  13. Run the following substeps in parallel: +
      +
    1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument.
    2. +
    3. If registration is not null, then: +
        +
      1. Resolve promise with the {{ServiceWorkerRegistration}} object which represents registration.
      2. +
      +
    4. +
    5. Else: +
        +
      1. Resolve promise with undefined.
      2. +
      +
    6. +
    +
  14. +
  15. Return promise.
  16. +
+
+ +
+ + +

getRegistrations() method must run these steps or their equivalent:

+ +
    +
  1. Let client be the context object's service worker client.
  2. +
  3. If client is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  4. +
  5. Let promise be a new promise.
  6. +
  7. Run the following substeps in parallel: +
      +
    1. Let array be an empty array.
    2. +
    3. For each Record {\[[key]], \[[value]]} entry of scope to registration map: +
        +
      1. If the origin of the result of parsing entry.\[[key]] is the same as client's origin, add the {{ServiceWorkerRegistration}} object associated with entry.\[[value]] to the array.
      2. +
      +
    4. +
    5. Resolve promise with array.
    6. +
    +
  8. +
  9. Return promise.
  10. +
+
+ +
+

Event handlers

+ +

The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

+ + + + + + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oncontrollerchangecontrollerchange
onerrorerror
onmessagemessage
+
+
+ +
+

{{ServiceWorkerMessageEvent}}

+ +
+      [Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
+      interface ServiceWorkerMessageEvent : Event {
+        readonly attribute any data;
+        readonly attribute DOMString origin;
+        readonly attribute DOMString lastEventId;
+        [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
+        [SameObject] readonly attribute MessagePort[]? ports;
+      };
+    
+
+      dictionary ServiceWorkerMessageEventInit : EventInit {
+        any data;
+        DOMString origin;
+        DOMString lastEventId;
+        (ServiceWorker or MessagePort)? source;
+        sequence<MessagePort>? ports;
+      };
+    
+ +

Service workers define the message event that extends the {{Window/message}} event defined in [[!HTML]] to allow setting a {{ServiceWorker}} object as the source of the message. For the message event, service workers use the ServiceWorkerMessageEvent interface.

+ +
+

{{ServiceWorkerMessageEvent/data|event.data}}

+ +

The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

+
+ +
+

{{ServiceWorkerMessageEvent/origin|event.origin}}

+ +

The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker's environment settings object from which the message is sent.

+
+ +
+

{{ServiceWorkerMessageEvent/lastEventId|event.lastEventId}}

+ +

The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

+
+ +
+

{{ServiceWorkerMessageEvent/source|event.source}}

+ +

The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the ServiceWorker object whose associated service worker the message is sent from.

+
+ +
+

{{ServiceWorkerMessageEvent/ports|event.ports}}

+ +

The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{MessagePort}} array being sent, if any.

+
+
+ +
+

Events

+ +

The following event is dispatched on {{ServiceWorker}} object:

+ + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
statechange{{Event}}The {{ServiceWorker/state}} attribute of the {{ServiceWorker}} object is changed.
+ +

The following event is dispatched on {{ServiceWorkerRegistration}} object:

+ + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
updatefound{{Event}}The service worker registration's installing worker changes. (See step 7 of the Install algorithm.)
+ +

The following events are dispatched on {{ServiceWorkerContainer}} object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
controllerchange{{Event}}The service worker client's active worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} immediately reflects the active worker as the service worker that controls the service worker client.)
message{{ServiceWorkerMessageEvent}}When it receives a message.
error{{ErrorEvent}}Any error occurred from the associated service workers.
+
+
+ +
+

Execution Context

+ +
+ Serving Cached Resources: + +
+      // caching.js
+      this.addEventListener("install", function(e) {
+        e.waitUntil(
+          // Open a cache of resources.
+          caches.open("shell-v1").then(function(cache) {
+            // Begins the process of fetching them.
+            // The coast is only clear when all the resources are ready.
+            return cache.addAll([
+              "/app.html",
+              "/assets/v1/base.css",
+              "/assets/v1/app.js",
+              "/assets/v1/logo.png",
+              "/assets/v1/intro_video.webm"
+            ]);
+          })
+        );
+      });
+
+      this.addEventListener("fetch", function(e) {
+        // No "fetch" events are dispatched to the service worker until it
+        // successfully installs and activates.
+
+        // All operations on caches are async, including matching URLs, so we use
+        // promises heavily. e.respondWith() even takes promises to enable this:
+        e.respondWith(
+          caches.match(e.request).then(function(response) {
+            return response || fetch(e.request);
+          }).catch(function() {
+            return caches.match("/fallback.html");
+          })
+        );
+      });
+    
+
+ +
+

{{ServiceWorkerGlobalScope}}

+ +
+      [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
+      interface ServiceWorkerGlobalScope : WorkerGlobalScope {
+        // A container for a list of Client objects that correspond to
+        // browsing contexts (or shared workers) that are on the origin of this SW
+        [SameObject] readonly attribute Clients clients;
+        [SameObject] readonly attribute ServiceWorkerRegistration registration;
+
+        [NewObject] Promise<void> skipWaiting();
+
+        attribute EventHandler oninstall;
+        attribute EventHandler onactivate;
+        attribute EventHandler onfetch;
+        attribute EventHandler onforeignfetch;
+
+        // event
+        attribute EventHandler onmessage; // event.source of the message events is Client object
+
+        // close() method inherited from WorkerGlobalScope should not be accessible.
+      };
+    
+ +

A ServiceWorkerGlobalScope object represents the global execution context of a service worker. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a service worker).

+ +

{{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

+ +

The {{WorkerGlobalScope/close()}} method inherited from {{WorkerGlobalScope}}, when called on the context object, should throw an "{{InvalidAccessError}}" exception.

+ +
+

{{ServiceWorkerGlobalScope/clients}}

+ +

clients attribute must return the {{Clients}} object that is associated with the context object.

+
+ +
+

{{ServiceWorkerGlobalScope/registration}}

+ +

The registration attribute must return the {{ServiceWorkerRegistration}} object that represents the service worker's containing service worker registration.

+
+ +
+

{{ServiceWorkerGlobalScope/skipWaiting()}}

+ +

The {{ServiceWorkerGlobalScope/skipWaiting()}} method allows this service worker to progress from the registration's waiting position to active even while service worker clients are using the registration.

+ +

skipWaiting() method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run the following substeps in parallel: +
      +
    1. Set service worker's skip waiting flag
    2. +
    3. If service worker's state is installed, then: +
        +
      1. Run Activate algorithm, or its equivalent, passing service worker's registration as the argument.
      2. +
      +
    4. +
    5. Resolve promise with undefined.
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+ +
+

Event handlers

+ +

The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
event handlerevent handler event type
oninstallinstall
onactivateactivate
onfetchfetch
onforeignfetchforeignfetch
onmessagemessage
+
+
+ +
+

{{Client}}

+ +
+      [Exposed=ServiceWorker]
+      interface Client {
+        readonly attribute USVString url;
+        readonly attribute FrameType frameType;
+        readonly attribute DOMString id;
+        void postMessage(any message, optional sequence<Transferable> transfer);
+      };
+
+      [Exposed=ServiceWorker]
+      interface WindowClient : Client {
+        readonly attribute VisibilityState visibilityState;
+        readonly attribute boolean focused;
+        [NewObject] Promise<WindowClient> focus();
+        [NewObject] Promise<WindowClient> navigate(USVString url);
+      };
+
+      enum FrameType {
+        "auxiliary",
+        "top-level",
+        "nested",
+        "none"
+      };
+    
+ +

A Client object has an associated service worker client (a service worker client).

+ +

A WindowClient object has an associated visibility state, which is one of {{Document/visibilityState}} attribute value.

+ +

A {{WindowClient}} object has an associated focus state, which is either true or false (initially false).

+ +
+

{{Client/url}}

+ +

The url attribute must return the context object's associated service worker client's serialized creation url.

+
+ +
+

{{Client/frameType}}

+ +

The frameType attribute must return the value (in FrameType enumeration) corresponding to the first matching statement, switching on service worker client's frame type:

+ +
+
auxiliary
+
"auxiliary" +

The window client's global object's browsing context is an auxiliary browsing context.

+ +
top-level
+
"top-level" +

The window client's global object's browsing context is a top-level browsing context.

+ +
nested
+
"nested" +

The window client's global object's browsing context is a nested browsing context.

+ +
none
+
"none"
+
+
+ +
+

{{Client/id}}

+ +

The id attribute must return its associated service worker client's id.

+
+ +
+

{{Client/postMessage(message, transfer)}}

+ +

The postMessage(message, transfer) method must run these steps or their equivalent:

+ +
    +
  1. Let newPorts be an empty array.
  2. +
  3. Let transferMap be an empty association list of {{Transferable}} objects to placeholder objects.
  4. +
  5. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. If any object is listed in transfer more than once, or any of the {{Transferable}} objects listed in transfer are marked as neutered, then throw a "{{DataCloneError}}" exception and abort these steps.
    2. +
    3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a {{MessagePort}} object, also append the placeholder object to newPorts.
    4. +
    +
  6. +
  7. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
  8. +
  9. Let destination be the {{ServiceWorkerContainer}} object whose service worker client is the context object's service worker client.
  10. +
  11. If destination is null, throw an "{{InvalidStateError}}" exception.
  12. +
  13. If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. Let newOwner be the destination's service worker client.
    2. +
    3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
    4. +
    +
  14. +
  15. Make newPorts into a read only array.
  16. +
  17. Queue a task that runs the following steps: +
      +
    1. Create an event e that uses the {{ServiceWorkerMessageEvent}} interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Let the {{ServiceWorkerMessageEvent/data}} attribute of e be initialized to clonedMessage.
    4. +
    5. Let the {{ServiceWorkerMessageEvent/origin}} attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
    6. +
    7. Let the {{ServiceWorkerMessageEvent/source}} attribute of e be initialized to a {{ServiceWorker}} object, which represents the service worker associated with the global object specified by the incumbent settings object.
    8. +
    9. Let the {{ServiceWorkerMessageEvent/ports}} attribute of e be initialized to newPorts.
    10. +
    11. Dispatch e at destination.
    12. +
    +

    The task must use the DOM manipulation task source, and, for those where the event loop specified by the target {{ServiceWorkerContainer}} object's service worker client is a browsing context event loop, must be associated with the responsible document specified by that target {{ServiceWorkerContainer}} object's service worker client.

    +
  18. +
+
+ +
+

{{WindowClient/visibilityState}}

+ +

The visibilityState attribute must return the context object's visibility state.

+
+ +
+

{{WindowClient/focused}}

+ +

The focused attribute must return the context object's focus state.

+
+ +
+

{{WindowClient/focus()}}

+ +

The focus() method must run these steps or their equivalent:

+ +
    +
  1. If this algorithm is not allowed to show a popup, return a promise rejected with an "{{InvalidAccessError}}" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run these substeps in parallel: +
      +
    1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
    2. +
    3. Let visibilityState be null.
    4. +
    5. Let focusState be null.
    6. +
    7. Queue a task task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
        +
      1. Run the focusing steps with browsingContext.
      2. +
      3. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
      4. +
      5. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
      6. +
      +
    8. +
    9. Wait for task to have executed.
    10. +
    11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with the context object's associated service worker client, visibilityState and focusState as the arguments.
    12. +
    13. If windowClient's focus state is true, resolve promise with windowClient.
    14. +
    15. Else, reject promise with a TypeError.
    16. +
    +
  6. +
  7. Return promise.
  8. +
+
+ +
+

{{WindowClient/navigate(url)}}

+ +

The navigate() method must run these steps or their equivalent:

+ +
    +
  1. Let url be the result of parsing url with entry settings object's API base URL.
  2. +
  3. If url is failure, return a promise rejected with a TypeError.
  4. +
  5. If url is about:blank, return a promise rejected with a TypeError.
  6. +
  7. If the context object's associated service worker client's active worker is not the incumbent settings object's global object's service worker, return a promise rejected with a TypeError.
  8. +
  9. Let promise be a new promise.
  10. +
  11. Run these substeps in parallel: +
      +
    1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
    2. +
    3. If browsingContext has discarded its {{Document}}, reject promise with a TypeError and abort these steps.
    4. +
    5. Let navigateFailed to false.
    6. +
    7. Let visibilityState be null.
    8. +
    9. Let focusState be null.
    10. +
    11. Queue a task task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
        +
      1. HandleNavigate: Navigate browsingContext to url with replacement enabled and exceptions enabled. The source browsing context must be browsingContext.
      2. +
      3. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set navigateFailed to true.
      4. +
      5. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
      6. +
      7. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
      8. +
      +
    12. +
    13. Wait for task to have executed (including its asynchronous steps).
    14. +
    15. If navigateFailed is true, reject promise with a TypeError and abort these steps.
    16. +
    17. If browsingContext's {{Window}} object's environment settings object's creation url's origin is not the same as the service worker's origin, then: +
        +
      1. Resolve promise with null.
      2. +
      3. Abort these steps.
      4. +
      +
    18. +
    19. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with browsingContext's {{Window}} object's environment settings object, visibilityState and focusState as the arguments.
    20. +
    21. Resolve promise with windowClient.
    22. +
    +
  12. +
  13. Return promise.
  14. +
+
+
+ +
+

{{Clients}}

+ +
+      [Exposed=ServiceWorker]
+      interface Clients {
+        // The objects returned will be new instances every time
+        [NewObject] Promise<any> get(DOMString id);
+        [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
+        [NewObject] Promise<WindowClient?> openWindow(USVString url);
+        [NewObject] Promise<void> claim();
+      };
+    
+
+      dictionary ClientQueryOptions {
+        boolean includeUncontrolled = false;
+        ClientType type = "window";
+      };
+    
+
+      enum ClientType {
+        "window",
+        "worker",
+        "sharedworker",
+        "all"
+      };
+    
+ +

The user agent must create a Clients object when a ServiceWorkerGlobalScope object is created and associate it with that object.

+ +
+

{{Clients/get(id)}}

+ +

The get(id) method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run these substeps in parallel: +
      +
    1. For each service worker client client whose origin is the same as the associated service worker's origin: +
        +
      1. If client's id is id, then: +
          +
        1. If client is not a secure context, reject promise with a "{{SecurityError}}" exception and abort these steps.
        2. +
        3. If client is a window client, then: +
            +
          1. Let browsingContext be client's global object's browsing context.
          2. +
          3. Let visibilityState be null.
          4. +
          5. Let focusState be null.
          6. +
          7. Queue a task task to run the following substeps: +
              +
            1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
            2. +
            3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
            4. +
            +
          8. +
          9. Wait for task to have executed.
          10. +
          11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
          12. +
          13. Resolve promise with windowClient and abort these steps.
          14. +
          +
        4. +
        5. Else: +
            +
          1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
          2. +
          3. Resolve promise with clientObject and abort these steps.
          4. +
          +
        6. +
        +
      2. +
      +
    2. +
    3. Resolve promise with undefined.
    4. +
    +
  4. +
  5. Return promise.
  6. +
+
+ +
+

{{Clients/matchAll(options)}}

+ +

The matchAll(options) method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run these substeps in parallel: +
      +
    1. Let targetClients be an empty array.
    2. +
    3. For each service worker client client whose origin is the same as the associated service worker's origin: +
        +
      1. If client is not a secure context, continue to the next iteration of the loop.
      2. +
      3. If options.{{ClientQueryOptions/includeUncontrolled}} is false, then: +
          +
        1. If client's active worker is the associated service worker, add client to targetClients.
        2. +
        +
      4. +
      5. Else: +
          +
        1. Add client to targetClients.
        2. +
        +
      6. +
      +
    4. +
    5. Let matchedClients be an empty array.
    6. +
    7. For each service worker client client in targetClients, in the most recently focused order for window clients: +
        +
      1. If options.{{ClientQueryOptions/type}} is "window", and client is a window client, then: +
          +
        1. Let browsingContext be client's global object's browsing context.
        2. +
        3. Let visibilityState be null.
        4. +
        5. Let focusState be null.
        6. +
        7. Queue a task task to run the following substeps on client's responsible event loop using the user interaction task source: +
            +
          1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
          2. +
          3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
          4. +
          +
        8. +
        9. Wait for task to have executed. +

          Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

          +
        10. +
        11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
        12. +
        13. Add windowClient to matchedClients.
        14. +
        +
      2. +
      3. Else if options.{{ClientQueryOptions/type}} is "worker" and client is a dedicated worker client, or options.{{ClientQueryOptions/type}} is "sharedworker" and client is a shared worker client, then: +
          +
        1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
        2. +
        3. Add clientObject to matchedClients.
        4. +
        +
      4. +
      5. Else if options.{{ClientQueryOptions/type}} is "all", then: +
          +
        1. If client is a window client, then: +
            +
          1. Let browsingContext be client's global object's browsing context.
          2. +
          3. Let visibilityState be null.
          4. +
          5. Let focusState be null.
          6. +
          7. Queue a task task to run the following substeps on client's responsible event loop using the user interaction task source: +
              +
            1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
            2. +
            3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
            4. +
            +
          8. +
          9. Wait for task to have executed. +

            Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

            +
          10. +
          11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
          12. +
          13. Add windowClient to matchedClients.
          14. +
          +
        2. +
        3. Else: +
            +
          1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
          2. +
          3. Add clientObject to matchedClients.
          4. +
          +
        4. +
        +
      +
    8. +
    9. Resolve promise with matchedClients.
    10. +
    +
  4. +
  5. Return promise.
  6. +
+
+ +
+

{{Clients/openWindow(url)}}

+ +

The openWindow(url) method must run these steps or their equivalent:

+ +
    +
  1. Let url be the result of parsing url with entry settings object's API base URL.
  2. +
  3. If url is failure, return a promise rejected with a TypeError.
  4. +
  5. If url is about:blank, return a promise rejected with a TypeError.
  6. +
  7. If this algorithm is not allowed to show a popup, return a promise rejected with an "<{{InvalidAccessError}}" exception.
  8. +
  9. Let promise be a new promise.
  10. +
  11. Run these substeps in parallel: +
      +
    1. Let newContext be a new top-level browsing context.
    2. +
    3. Let openWindowFailed to false.
    4. +
    5. Let visibilityState be null.
    6. +
    7. Let focusState be null.
    8. +
    9. Queue a task task to run the following substeps on newContext's {{Window}} object's environment settings object's responsible event loop using the user interaction task source: +
        +
      1. HandleNavigate: Navigate newContext to url, with exceptions enabled and replacement enabled.
      2. +
      3. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set openWindowFailed to true.
      4. +
      5. Set visibilityState to newContext's active document's {{Document/visibilityState}} attribute value.
      6. +
      7. Set focusState to the result of running the has focus steps with newContext's active document as the argument.
      8. +
      +
    10. +
    11. Wait for task to have executed (including its asynchronous steps).
    12. +
    13. If openWindowFailed is true, reject promise with a TypeError and abort these steps.
    14. +
    15. If newContext's {{Window}} object's environment settings object's creation url's origin is not the same as the service worker's origin, then: +
        +
      1. Resolve promise with null.
      2. +
      3. Abort these steps.
      4. +
      +
    16. +
    17. Let client be the result of running Create Window Client algorithm, or its equivalent, with newContext's {{Window}} object's environment settings object, visibilityState and focusState as the arguments.
    18. +
    19. Resolve promise with client.
    20. +
    +
  12. +
  13. Return promise.
  14. +
+
+ +
+

{{Clients/claim()}}

+ +

The claim() method must run these steps or their equivalent:

+ +
    +
  1. If the service worker is not an active worker, return a promise rejected with an "{{InvalidStateError}}" exception.
  2. +
  3. Let promise be a new promise.
  4. +
  5. Run the following substeps in parallel: +
      +
    1. For each service worker client client whose origin is the same as the service worker's origin: +
        +
      1. If client is not a secure context, continue to the next iteration of the loop.
      2. +
      3. Let registration be the result of running Match Service Worker Registration algorithm passing client's creation url as the argument.
      4. +
      5. If registration is not the service worker's containing service worker registration, continue to the next iteration of the loop.
      6. +
      7. If client's active worker is not the service worker, then: +
          +
        1. Invoke Handle Service Worker Client Unload with client as the argument.
        2. +
        3. Set client's active worker to service worker.
        4. +
        5. Invoke Notify Controller Change algorithm with client as the argument.
        6. +
        +
      8. +
      +
    2. +
    3. Resolve promise with undefined.
    4. +
    +
  6. +
  7. Return promise.
  8. +
+
+
+ +
+

{{ExtendableEvent}}

+ +
+      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
+      interface ExtendableEvent : Event {
+        void waitUntil(Promise<any> f);
+      };
+    
+
+      dictionary ExtendableEventInit : EventInit {
+        // Defined for the forward compatibility across the derived events
+      };
+    
+ +

An ExtendableEvent object has an associated extend lifetime promises (an array of promises). It is initially set to null.

+ +

Service workers have two lifecycle events, install and activate. Service workers use the {{ExtendableEvent}} interface for activate event and install event.

+ +

Service worker extensions that define event handlers may also use or extend the {{ExtendableEvent}} interface.

+ +
+

{{ExtendableEvent/waitUntil(f)|event.waitUntil(f)}}

+ +

{{ExtendableEvent/waitUntil(f)}} method extends the lifetime of the event.

+ +

waitUntil(f) method must run these steps or their equivalent:

+ +
    +
  1. If the dispatch flag is unset, then: +
      +
    1. Throw an "{{InvalidStateError}}" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. Add f to extend lifetime promises.
  4. +
+ +

In the task task in which the steps of waitUntil(f) is running, the user agent must run these steps or their equivalent:

+ +
    +
  1. Let extendLifetimePromises be an empty array.
  2. +
  3. For each event listener invoked: +
      +
    1. Let eventObject be the first argument passed to this event listener.
    2. +
    3. Append eventObject's extend lifetime promises to extendLifetimePromises.
    4. +
    +
  4. +
  5. Do not terminate the service worker whose responsible event loop is running task until waiting for all of extendLifetimePromises settles.
  6. +
+

However, the user agent may impose a time limit to this lifetime extension.

+ +

Service workers and extensions that define event handlers may define their own behaviors, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

+ +

Service workers define the following behaviors for install event and activate event:

+ +
    +
  • When called in {{ServiceWorkerGlobalScope/oninstall}}, it delays treating the installing worker as installed (i.e. a waiting worker) until the passed promise f resolves successfully. (See step 10.6.1 of Install algorithm.) If f rejects, the installation fails. This is primarily used to ensure that a service worker is not considered installed (i.e. a waiting worker) until all of the core caches it depends on are populated.
  • +
  • When called in {{ServiceWorkerGlobalScope/onactivate}}, it delays treating the active worker as activated until the passed promise f settles. (See step 13 of Activate algorithm.) This is primarily used to ensure that any functional events are not dispatched to the {{ServiceWorkerGlobalScope}} object that represents the service worker until it upgrades database schemas and deletes the outdated cache entries.
  • +
+
+
+ +
+

{{InstallEvent}}

+ +
+      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
+      interface InstallEvent : ExtendableEvent {
+        void registerForeignFetch(ForeignFetchOptions options);
+      };
+
+      dictionary ForeignFetchOptions {
+        required sequence<USVString> scopes;
+        required sequence<USVString> origins;
+      };
+    
+ +
+

{{InstallEvent/registerForeignFetch(options)|event.registerForeignFetch(options)}}

+ +

{{InstallEvent/registerForeignFetch(options)}} registers this service worker to handle foreign fetches from certain origins for certain sub scopes.

+ +

registerForeignFetch(options) method must run these steps or their equivalent:

+
    +
  1. If the dispatch flag is unset, then: +
      +
    1. Throw an "InvalidStateError" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. If options.{{ForeignFetchOptions/origins}} is empty throw a TypeError and abort these steps.
  4. +
  5. Let originURLs be an empty list of URLs.
  6. +
  7. If the value of options.{{ForeignFetchOptions/origins}} is not a single string equal to a single U+002A ASTERISK character (*): +
      +
    1. For each origin in options.origins: +
        +
      1. If the value of origin is not an absolute URL, throw a TypeError and abort these steps.
      2. +
      3. Add the result of parsing origin to originURLs.
      4. +
      +
    2. +
    +
  8. +
  9. If options.{{ForeignFetchOptions/scopes}} is empty throw a TypeError and abort these steps.
  10. +
  11. Let scopeString be the incumbent settings object's global object's service worker's containing service worker registration's scope url, serialized.
  12. +
  13. Let subScopeURLs be an empty list of URLs.
  14. +
  15. For each subScope in options.{{ForeignFetchOptions/scopes}}: +
      +
    1. Let subScopeURL be the result of parsing subScope with entry settings object's API base URL.
    2. +
    3. If subScopeURL is failure, throw a TypeError and abort these steps.
    4. +
    5. Let subScopeString be the serialized subScopeURL.
    6. +
    7. If subScopeString does not start with scopeString, throw a TypeError and abort these steps.
    8. +
    9. Add subScopeURL to subScopeURLs.
    10. +
    +
  16. +
  17. Set this service worker's list of foreign fetch scopes to subScopeURLs.
  18. +
  19. Set this service worker's list of foreign fetch origins to originURLs.
  20. +
+
+
+ +
+

{{FetchEvent}}

+ +
+      [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
+      interface FetchEvent : ExtendableEvent {
+        [SameObject] readonly attribute Request request;
+        readonly attribute DOMString? clientId;
+        readonly attribute boolean isReload;
+
+        void respondWith(Promise<Response> r);
+      };
+    
+
+      dictionary FetchEventInit : ExtendableEventInit {
+        required Request request;
+        DOMString? clientId = null;
+        boolean isReload = false;
+      };
+    
+ +

Service workers have an essential functional event fetch. For fetch event, service workers use the FetchEvent interface which extends the {{ExtendableEvent}} interface.

+ +

Each event using {{FetchEvent}} interface has an associated potential response (a response), initially set to null, and the following associated flags that are initially unset: +

    +
  • wait to respond flag
  • +
  • respond-with entered flag
  • +
  • respond-with error flag
  • +
+

+ +
+

{{FetchEvent/request|event.request}}

+ +

request attribute must return the value it was initialized to.

+
+ +
+

{{FetchEvent/clientId|event.clientId}}

+ +

clientId attribute must return the value it was initialized to. When an event is created the attribute must be initialized to null.

+
+ +
+

{{FetchEvent/isReload|event.isReload}}

+ +

isReload attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

+ +

Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

+
+ +
+

{{FetchEvent/respondWith(r)|event.respondWith(r)}}

+ +

Developers can set the argument r with either a promise that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

+ +

respondWith(r) method must run these steps or their equivalent:

+ +
    +
  1. If the dispatch flag is unset, then: +
      +
    1. Throw an "{{InvalidStateError}}" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. If the respond-with entered flag is set, then: +
      +
    1. Throw an "{{InvalidStateError}}" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  4. +
  5. Set the stop propagation flag and stop immediate propagation flag.
  6. +
  7. Set the respond-with entered flag.
  8. +
  9. Set the wait to respond flag.
  10. +
  11. Run the following substeps in parallel: +
      +
    1. Wait until r settles.
    2. +
    3. If r rejected, then: +
        +
      1. Set the respond-with error flag.
      2. +
      +
    4. +
    5. If r resolved with response, then: +
        +
      1. If response is a {{Response}} object, then: +
          +
        1. If response is disturbed or locked, then: +
            +
          1. Set the respond-with error flag.
          2. +
          +
        2. +
        3. Else: +
            +
          1. Let potentialResponse be a copy of response's associated response, except for its body.
          2. +
          3. If response's body is non-null, run these substeps: +
              +
            1. Set potentialResponse's body to response's body.
            2. +
            3. Let dummyStream be an empty ReadableStream object.
            4. +
            5. Set response's body to a new body whose stream is dummyStream.
            6. +
            7. Let reader be the result of getting a reader from dummyStream.
            8. +
            9. Read all bytes from dummyStream with reader.
            10. +
            +

            These substeps are meant to produce the observable equivalent of "piping" response's body's stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse's body's stream is now equal to what used to be response's, if response's original body is non-null.

            +

            These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

            +
          4. +
          5. Set the potential response to potentialResponse.
          6. +
          +
        4. +
        +
      2. +
      3. Else: +
          +
        1. Set the respond-with error flag.
        2. +
        +

        If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 22.1.)

        +
      4. +
      +
    6. +
    7. Unset the wait to respond flag.
    8. +
    +
  12. +
+
+
+ +
+

{{ForeignFetchEvent}}

+ +
+      [Constructor(DOMString type, ForeignFetchEventInit eventInitDict), Exposed=ServiceWorker]
+      interface ForeignFetchEvent : ExtendableEvent {
+        [SameObject] readonly attribute Request request;
+
+        void respondWith(Promise<ForeignFetchResponse> r);
+      };
+
+      dictionary ForeignFetchEventInit : ExtendableEventInit {
+        required Request request;
+      };
+
+      dictionary ForeignFetchResponse {
+        required Response response;
+        USVString origin;
+        sequence<ByteString> headers;
+      };
+    
+ +

Service workers have a functional event foreignfetch. For foreignfetch events, service workers use the ForeignFetchEvent interface which extends the {{ExtendableEvent}} interface.

+ +

Each event using {{ForeignFetchEvent}} interface has an associated potential response (a response), initially set to null, an associated origin (a URL), initially set to null, an associated list of exposed headers (whose element type is a byte string), initially set to an empty list, and the following associated flags that are initially unset: +

    +
  • wait to respond flag
  • +
  • respond-with entered flag
  • +
  • respond-with error flag
  • +
+

+ +
+

{{ForeignFetchEvent/request|event.request}}

+ +

request attribute must return the value it was initialized to.

+
+ +
+

{{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}}

+ +

Developers can set the argument r with either a promise that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

+ +

respondWith(r) method must run these steps or their equivalent:

+ +
    +
  1. If the dispatch flag is unset, then: +
      +
    1. Throw an "{{InvalidStateError}}" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  2. +
  3. If the respond-with entered flag is set, then: +
      +
    1. Throw an "{{InvalidStateError}}" exception.
    2. +
    3. Abort these steps.
    4. +
    +
  4. +
  5. Set the stop propagation flag and stop immediate propagation flag.
  6. +
  7. Set the respond-with entered flag.
  8. +
  9. Set the wait to respond flag.
  10. +
  11. Run the following substeps in parallel: +
      +
    1. Wait until r settles.
    2. +
    3. If r rejected, then: +
        +
      1. Set the respond-with error flag.
      2. +
      +
    4. +
    5. If r resolved with response, then: +
        +
      1. If response is a {{ForeignFetchResponse}}, then: +
          +
        1. Set the event's origin to response.{{ForeignFetchResponse/origin}}.
        2. +
        3. Set the event's list of exposed headers to response.{{ForeignFetchResponse/headers}}.
        4. +
        5. If response.{{ForeignFetchResponse/response}} is disturbed or locked, then: +
            +
          1. Set the respond-with error flag.
          2. +
          +
        6. +
        7. Else: +
            +
          1. Let potentialResponse be a copy of response.{{ForeignFetchResponse/response}}'s associated response, except for its body.
          2. +
          3. If response.{{ForeignFetchResponse/response}}'s body is non-null, run these substeps: +
              +
            1. Set potentialResponse's body to response.{{ForeignFetchResponse/response}}'s body.
            2. +
            3. Let dummyStream be an empty ReadableStream object.
            4. +
            5. Set response.{{ForeignFetchResponse/response}}'s body to a new body whose stream is dummyStream.
            6. +
            7. Let reader be the result of getting a reader from dummyStream.
            8. +
            9. Read all bytes from dummyStream with reader.
            10. +
            +

            These substeps are meant to produce the observable equivalent of "piping" response's body's stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse's body's stream is now equal to what used to be response's, if response's original body is non-null.

            +

            These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

            +
          4. +
          5. Set the potential response to potentialResponse.
          6. +
          +
        8. +
        +
      2. +
      3. Else: +
          +
        1. Set the respond-with error flag.
        2. +
        +

        If the respond-with error flag is set, a network error is returned to Fetch through [[#on-foreign-fetch-request-algorithm]] algorithm. (See the step 21.1.) Otherwise, a filtered version of response is returned to Fetch through [[#on-foreign-fetch-request-algorithm]] algorithm. (See the step 22.1.)

        +
      4. +
      +
    6. +
    7. Unset the wait to respond flag.
    8. +
    +
  12. +
+
+
+ +
+

{{ExtendableMessageEvent}}

+ +
+      [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
+      interface ExtendableMessageEvent : ExtendableEvent {
+        readonly attribute any data;
+        readonly attribute DOMString origin;
+        readonly attribute DOMString lastEventId;
+        [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
+        [SameObject] readonly attribute MessagePort[]? ports;
+      };
+    
+
+      dictionary ExtendableMessageEventInit : ExtendableEventInit {
+        any data;
+        DOMString origin;
+        DOMString lastEventId;
+        (Client or ServiceWorker or MessagePort)? source;
+        sequence<MessagePort>? ports;
+      };
+    
+ +

Service workers define the extendable message event that extends the {{Window/message}} event defined in [[!HTML]] to allow extending the lifetime of the event. For the message event, service workers use the ExtendableMessageEvent interface which extends the {{ExtendableEvent}} interface.

+ +
+

{{ExtendableMessageEvent/data|event.data}}

+ +

The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

+
+ +
+

{{ExtendableMessageEvent/origin|event.origin}}

+ +

The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker client that sent the message.

+
+ +
+

{{ExtendableMessageEvent/lastEventId|event.lastEventId}}

+ +

The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

+
+ +
+

{{ExtendableMessageEvent/source|event.source}}

+ +

The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{Client}} object from which the message is sent.

+
+ +
+

{{ExtendableMessageEvent/ports|event.ports}}

+ +

The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{MessagePort}} array being sent, if any.

+
+
+ +
+

Events

+ +

The following events are dispatched on ServiceWorkerGlobalScope object:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Event nameInterfaceDispatched when…
install{{InstallEvent}}[Lifecycle event] The service worker's containing service worker registration's installing worker changes. (See step 11.2 of the Install algorithm.)
activate{{ExtendableEvent}}[Lifecycle event] The service worker's containing service worker registration's active worker changes. (See step 15.2 of the Activate algorithm.)
fetch{{FetchEvent}}[Functional event] The http fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the service worker returns a response to the http fetch. The response, represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{GlobalFetch/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
foreignfetch{{FetchEvent}}[Functional event] The http fetch invokes [[#on-foreign-fetch-request-algorithm]] with request. As a result of performing [[#on-foreign-fetch-request-algorithm]], the service worker returns a response to the http fetch. The response, represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{GlobalFetch/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
message{{ExtendableMessageEvent}}When it receives a message.
+
+
+ + +
+

Caches

+ +

To allow authors to fully manage their content caches for offline use, the {{Window}} and the {{WorkerGlobalScope}} provide the asynchronous caching methods that open and manipulate {{Cache}} objects. An origin can have multiple, named {{Cache}} objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser's HTTP cache.

+ +
+

Constructs

+ +

A fetching record is a Record {\[[key]], \[[value]]} where \[[key]] is a {{Request}} and \[[value]] is a {{Response}}.

+

A fetching record has an associated incumbent record (a fetching record). It is initially set to null.

+

A request to response map is a List of fetching records.

+ +

A name to cache map is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a string that represents a name of the {{Cache}} object and \[[value]] is a {{Cache}} object.

+ +

Each origin has an associated name to cache map.

+
+ +
+

Understanding Cache Lifetimes

+ +

The {{Cache}} instances are not part of the browser's HTTP cache. The {{Cache}} objects are exactly what authors have to manage themselves. The {{Cache}} objects do not get updated unless authors explicitly request them to be. The {{Cache}} objects do not expire unless authors delete the entries. The {{Cache}} objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

+
+ +
+

{{Window/caches|self.caches}}

+ +
+      partial interface Window {
+        [SameObject] readonly attribute CacheStorage caches;
+      };
+
+      partial interface WorkerGlobalScope {
+        [SameObject] readonly attribute CacheStorage caches;
+      };
+    
+ +
+

{{Window/caches}}

+ +

caches attribute must return the {{CacheStorage}} object that is associated with the context object.

+
+
+ +
+

{{Cache}}

+ +
+      [Exposed=(Window,Worker)]
+      interface Cache {
+        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
+        [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
+        [NewObject] Promise<void> add(RequestInfo request);
+        [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
+        [NewObject] Promise<void> put(RequestInfo request, Response response);
+        [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
+        [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
+      };
+    
+
+      dictionary CacheQueryOptions {
+        boolean ignoreSearch = false;
+        boolean ignoreMethod = false;
+        boolean ignoreVary = false;
+        DOMString cacheName;
+      };
+    
+
+      dictionary CacheBatchOperation {
+        DOMString type;
+        Request request;
+        Response response;
+        CacheQueryOptions options;
+      };
+    
+ +

A Cache object represents a request to response map. Multiple separate objects implementing the {{Cache}} interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

+ +

{{Cache}} objects are always enumerable via {{Window/caches|self.caches}} in insertion order (per ECMAScript 6 Map objects).

+ +
+

{{Cache/match(request, options)}}

+ +

match(request, options) method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run these substeps in parallel: +
      +
    1. Let p be the result of running the algorithm specified in {{Cache/matchAll(request, options)}} method with request and options as the arguments.
    2. +
    3. Wait until p settles.
    4. +
    5. If p rejects with an exception, then: +
        +
      1. Reject promise with that exception.
      2. +
      +
    6. +
    7. Else if p resolves with an array, responseArray, then: +
        +
      1. If responseArray is an empty array, then: +
          +
        1. Resolve promise with undefined.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Resolve promise with the first element of responseArray.
        2. +
        +
      4. +
      +
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+ +
+

{{Cache/matchAll(request, options)}}

+ +

matchAll(request, options) method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run these substeps in parallel: +
      +
    1. Let responseArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add a copy of entry.\[[value]] to responseArray.
        2. +
        +
      2. +
      3. Resolve promise with responseArray.
      4. +
      5. Abort these steps.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a {{Request}} object, then: +
          +
        1. Set r to request's request.
        2. +
        3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
        4. +
        +
      4. +
      5. Else if request is a string, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let entries be the result of running Query Cache algorithm passing a {{Request}} object associated with r and options as the arguments.
      10. +
      11. For each entry of entries: +
          +
        1. Let response be null.
        2. +
        3. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, set response to a copy of incumbentRecord.\[[value]].
        4. +
        5. Else, set response to a copy of entry[1].
        6. +
        7. If r's method is `HEAD` and options.ignoreMethod is false, then: +
            +
          1. Let actualResponse be response's associated response, if response's associated response is not a filtered response, and to response's associated response's internal response otherwise.
          2. +
          3. Set actualResponse's body to null.
          4. +
          +
        8. +
        9. Add response to responseArray.
        10. +
        +
      12. +
      13. Resolve promise with responseArray.
      14. +
      +
    6. +
    +
  4. +
  5. Return promise.
  6. +
+
+ +
+

{{Cache/add(request)}}

+ +

add(request) method must run these steps or their equivalent:

+ +
    +
  1. Let requests be an array containing only request.
  2. +
  3. Set responseArrayPromise to the result of running the algorithm specified in {{Cache/addAll(requests)}} passing requests as the argument.
  4. +
  5. Return the result of transforming responseArrayPromise with a fulfillment handler that returns undefined.
  6. +
+
+ +
+

{{Cache/addAll(requests)}}

+ +

addAll(requests) method must run these steps or their equivalent:

+ +
    +
  1. Let responsePromiseArray be an empty array.
  2. +
  3. Let requestArray be an empty array.
  4. +
  5. For each request whose type is {{Request}} in requests: +
      +
    1. Let r be request's request.
    2. +
    3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
    4. +
    +
  6. +
  7. For each request in requests: +
      +
    1. Let r be the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    3. If r's url's scheme is not one of "http" and "https", then: +
        +
      1. Terminate all the ongoing fetches initiated by requests with reason fatal.
      2. +
      3. Break the loop.
      4. +
      +
    4. +
    5. Set r's url's fragment to null.
    6. +
    7. Set r's initiator to "fetch" and destination to "subresource".
    8. +
    9. Add a {{Request}} object associated with r to requestArray.
    10. +
    11. Let responsePromise be a new promise.
    12. +
    13. Run the following substeps in parallel: +
        +
      • Fetch r.
      • +
      • To process response for response, run these substeps: +
          +
        1. If response's type is error, or response's status is not an ok status, reject responsePromise with a TypeError.
        2. +
        3. Else if response's header list contains a header named `Vary`, then: +
            +
          1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
          2. +
          3. Let matchAsterisk be false.
          4. +
          5. For each f in varyHeaders: +
              +
            1. If f matches "*", set matchAsterisk to true and break the loop.
            2. +
            +
          6. +
          7. If matchAsterisk is true, reject responsePromise with a TypeError.
          8. +
          9. Else, resolve responsePromise with a new {{Response}} object associated with response and a new {{Headers}} object whose guard is "immutable".
          10. +
          +
        4. +
        5. Else, resolve responsePromise with a new {{Response}} object associated with response and a new {{Headers}} object whose guard is "immutable".
        6. +
        +

        This step ensures that the promise for this fetch resolves as soon as the response's headers become available.

        +
      • +
      • To process response body for response, do nothing.
      • +
      • To process response end-of-file for response, do nothing.
      • +
      +
    14. +
    15. Add responsePromise to responsePromiseArray.
    16. +
    +
  8. +
  9. Let p be waiting for all of responsePromiseArray.
  10. +
  11. Return the result of transforming p with a fulfillment handler that, when called with argument responseArray, performs the following substeps in parallel: +
      +
    1. Let operations be an empty array.
    2. +
    3. For each response in responseArray with the index index: +
        +
      1. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
      2. +
      3. Set the {{CacheBatchOperation/type}} dictionary member of o to "put".
      4. +
      5. Set the {{CacheBatchOperation/request}} dictionary member of o to requestArray[index].
      6. +
      7. Set the {{CacheBatchOperation/response}} dictionary member of o to response.
      8. +
      9. Add o to operations.
      10. +
      +
    4. +
    5. Let resultPromise be the result of running Batch Cache Operations algorithm passing operations as the argument.
    6. +
    7. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
        +
      1. Let responseBodyPromiseArray be an empty array.
      2. +
      3. For each response in responses: +
          +
        1. Let responseBodyPromise be a new promise.
        2. +
        3. Run the following substeps in parallel: +
            +
          1. Wait for either end-of-file to have been pushed to response's associated response r's body or for r to have a termination reason.
          2. +
          3. If r had a termination reason, then: +
              +
            1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
                +
              1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
              2. +
              +
            2. +
            3. Else: +
                +
              1. Delete fetchingRecord from request to response map.
              2. +
              +
            4. +
            5. Reject responseBodyPromise with a TypeError.
            6. +
            +
          4. +
          5. Else: +
              +
            1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
            2. +
            3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.\[[key]] as the argument.
            4. +
            5. For each invalidRecord in invalidRecords: +
                +
              1. If invalidRecord is not fetchingRecord, delete it from request to response map.
              2. +
              +
            6. +
            7. Resolve responseBodyPromise with response.
            8. +
            +
          6. +
          +
        4. +
        5. Add responseBodyPromise to responseBodyPromiseArray.
        6. +
        +
      4. +
      5. Let q be waiting for all of responseBodyPromiseArray.
      6. +
      7. Return the result of transforming q with a fulfillment handler that returns undefined.
      8. +
      +
    8. +
    +
  12. +
+
+ +
+

{{Cache/put(request, response)}}

+ +

put(request, response) method must run these steps or their equivalent:

+ +
    +
  1. Let r be null.
  2. +
  3. If request is a {{Request}} object, then: +
      +
    1. Set r to request's request.
    2. +
    3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
    4. +
    +
  4. +
  5. Else if request is a string, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    3. If r's url's scheme is not one of "http" and "https", return a promise rejected with a TypeError.
    4. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. If response's associated response's header list contains a header named `Vary`, then: +
      +
    1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
    2. +
    3. For each f in varyHeaders: +
        +
      1. If f matches "*", return a promise rejected with a TypeError.
      2. +
      +
    4. +
    +
  10. +
  11. If response is disturbed or locked, return a promise rejected with a TypeError.
  12. +
  13. Let newResponse be a new {{Response}} object associated with response's associated response and a new {{Headers}} object whose guard is response's {{Headers}}' guard.
  14. +
  15. If response's body is non-null, run these substeps: +
      +
    1. Let dummyStream be an empty ReadableStream object.
    2. +
    3. Set response's body to a new body whose stream is dummyStream.
    4. +
    5. Let reader be the result of getting a reader from dummyStream.
    6. +
    7. Read all bytes from dummyStream with reader.
    8. +
    +
  16. +
  17. Let operations be an empty array.
  18. +
  19. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
  20. +
  21. Set the {{CacheBatchOperation/type}} dictionary member of o to "put".
  22. +
  23. Set the {{CacheBatchOperation/request}} dictionary member of o to a {{Request}} object associated with r.
  24. +
  25. Set the {{CacheBatchOperation/response}} dictionary member of o to newResponse.
  26. +
  27. Add o to operations.
  28. +
  29. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument.
  30. +
  31. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
      +
    1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r's body or for r to have a termination reason.
    2. +
    3. If r had a termination reason, then: +
        +
      1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
          +
        1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Delete fetchingRecord from request to response map.
        2. +
        +
      4. +
      5. Throw a TypeError.
      6. +
      +
    4. +
    5. Else: +
        +
      1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
      2. +
      3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.\[[key]] as the argument.
      4. +
      5. For each invalidRecord in invalidRecords: +
          +
        1. If invalidRecord is not fetchingRecord, delete it from request to response map.
        2. +
        +
      6. +
      7. Return undefined.
      8. +
      +
    6. +
    +
  32. +
+
+ +
+

{{Cache/delete(request, options)}}

+ +

delete(request, options) method must run these steps or their equivalent:

+ +
    +
  1. Let r be null.
  2. +
  3. If request is a {{Request}} object, then: +
      +
    1. Set r to request's request.
    2. +
    3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, return a promise resolved with false.
    4. +
    +
  4. +
  5. Else if request is a string, then: +
      +
    1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
    2. +
    +
  6. +
  7. Set r's url's fragment to null.
  8. +
  9. Let operations be an empty array.
  10. +
  11. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
  12. +
  13. Set the {{CacheBatchOperation/type}} dictionary member of o to "delete".
  14. +
  15. Set the {{CacheBatchOperation/request}} dictionary member of o to a {{Request}} object associated with r.
  16. +
  17. Set the {{CacheBatchOperation/options}} dictionary member of o to options.
  18. +
  19. Add o to operations.
  20. +
  21. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument.
  22. +
  23. Return the result of transforming resultPromise with a fulfillment handler, when called with argument responseArray, performs the following substeps in parallel: +
      +
    1. If responseArray is not null, return true.
    2. +
    3. Else, return false.
    4. +
    +
  24. +
+
+ +
+

{{Cache/keys(request, options)}}

+ +

keys(request, options) method must run these steps or their equivalent:

+ +
    +
  1. Let promise be a new promise.
  2. +
  3. Run these substeps in parallel: +
      +
    1. Let resultArray be an empty array.
    2. +
    3. If the optional argument request is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Add entry.\[[key]] to resultArray.
        2. +
        +
      2. +
      +
    4. +
    5. Else: +
        +
      1. Let r be null.
      2. +
      3. If request is a {{Request}} object, then: +
          +
        1. Set r to request's request.
        2. +
        3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
        4. +
        +
      4. +
      5. Else if request is a string, then: +
          +
        1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        +
      6. +
      7. Set r's url's fragment to null.
      8. +
      9. Let requestResponseArray be the result of running Query Cache algorithm passing a {{Request}} object that represents r and options as the arguments.
      10. +
      11. For each requestResponse in requestResponseArray: +
          +
        1. Add requestResponse[0] to resultArray.
        2. +
        +
      12. +
      +
    6. +
    7. Resolve promise with resultArray.
    8. +
    +
  4. +
  5. Return promise.
  6. +
+
+
+ +
+

{{CacheStorage}}

+ +
+      [Exposed=(Window,Worker)]
+      interface CacheStorage {
+        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
+        [NewObject] Promise<boolean> has(DOMString cacheName);
+        [NewObject] Promise<Cache> open(DOMString cacheName);
+        [NewObject] Promise<boolean> delete(DOMString cacheName);
+        [NewObject] Promise<sequence<DOMString>> keys();
+      };
+    
+ + +

{{CacheStorage}} interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

+ +

The user agent must create a {{CacheStorage}} object when a {{Window}} object or a {{WorkerGlobalScope}} object is created and associate it with that object.

+ +

A CacheStorage object represents a name to cache map of its associated global object's environment settings object's origin. Multiple separate objects implementing the {{CacheStorage}} interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

+ +
+

{{CacheStorage/match(request, options)}}

+ +

match(request, options) method must run these steps or their equivalent:

+ +
    +
  1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  2. +
  3. If options.{{CacheQueryOptions/cacheName}} is present, then: +
      +
    1. Return a new promise p and run the following substeps in parallel: +
        +
      1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. If options.{{CacheQueryOptions/cacheName}} matches entry.\[[key]], then: +
            +
          1. Resolve p with the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with request and options as the arguments (providing entry.\[[value]] as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.)
          2. +
          3. Abort these steps.
          4. +
          +
        2. +
        +
      2. +
      3. Reject p with a "{{NotFoundError}}" exception.
      4. +
      +
    2. +
    +
  4. +
  5. Else: +
      +
    1. Let p be a promise resolved with undefined.
    2. +
    3. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. Set p to the result of transforming itself with a fulfillment handler that, when called with argument v, performs the following substeps in parallel: +
          +
        1. If v is not undefined, return v.
        2. +
        3. Return the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with request and options as the arguments (providing entry.\[[value]] as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.)
        4. +
        +
      2. +
      +
    4. +
    5. Return p.
    6. +
    +
  6. +
+
+ +
+

{{CacheStorage/has(cacheName)}}

+ +

has(cacheName) method must run these steps or their equivalent:

+ +
    +
  1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  2. +
  3. Return a promise p resolved with the result of running the following substeps: +
      +
    1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.\[[key]], then: +
          +
        1. Return true.
        2. +
        +
      2. +
      +
    2. +
    3. Return false.
    4. +
    +
  4. +
+
+ +
+

{{CacheStorage/open(cacheName)}}

+ +

open(cacheName) method must run these steps or their equivalent:

+ +
    +
  1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  2. +
  3. Let p be a new promise.
  4. +
  5. Run the following substeps: +
      +
    1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. If cacheName matches entry.\[[key]], then: +
          +
        1. Resolve p with a new {{Cache}} object which is a copy of entry.\[[value]].
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      +
    2. +
    3. Let cache be a new {{Cache}} object.
    4. +
    5. Set a newly-created Record {\[[key]]: cacheName, \[[value]]: cache} to name to cache map. If this cache write operation failed due to exceeding the granted quota limit, reject p with a "{{QuotaExceededError}}" exception and abort these steps.
    6. +
    7. Resolve p with cache.
    8. +
    +
  6. +
  7. Return p.
  8. +
+
+ +
+

{{CacheStorage/delete(cacheName)}}

+ +

delete(cacheName) method must run these steps or their equivalent:

+ +
    +
  1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  2. +
  3. Let p be the result of running the algorithm specified in {{CacheStorage/has(cacheName)}} method with cacheName as the argument.
  4. +
  5. Return the result of transforming p with a fulfillment handler that, when called with argument cacheExists, performs the following substeps in parallel: +
      +
    1. If cacheExists is true, then: +
        +
      1. Delete a Record {\[[key]], \[[value]]} entry from its name to cache map where cacheName matches entry.\[[key]].
      2. +
      3. Return true.
      4. +
      5. Abort these steps.
      6. +
      +

      After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.

      +
    2. +
    3. Else: +
        +
      1. Return false.
      2. +
      +
    4. +
    +
  6. +
+
+ +
+

{{CacheStorage/keys()}}

+ +

keys() method must run these steps or their equivalent:

+ +

The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

+ +
    +
  1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
  2. +
  3. Let resultArray be an empty array.
  4. +
  5. Return a promise p resolved with the result of running the following substeps: +
      +
    1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
        +
      1. Add entry.\[[key]] to resultArray.
      2. +
      +
    2. +
    3. Return resultArray.
    4. +
    +
  6. +
+
+
+
+ +
+

Security Considerations

+ +
+

Secure Context

+ +

Service workers must execute in secure contexts. Service worker clients must also be secure contexts to register a service worker registration, to get access to the service worker registrations and the service workers, to do messaging with the service workers, and to be manipulated by the service workers. This effectively means that service workers and their service worker clients should be hosted over HTTPS. A user agent may allow localhost, 127.0.0.0/8, and ::1/128 for development purpose. (Note that they may still be secure contexts.) The primary reason for this restriction is to protect users from the risks associated with insecure contexts.

+
+ +
+

Content Security Policy

+ +

Whenever a user agent invokes Run Service Worker algorithm with a service worker serviceWorker: +

    +
  • If serviceWorker's script resource was delivered with a Content-Security-Policy HTTP header containing the value policy, the user agent must enforce policy for serviceWorker.
  • +
  • If serviceWorker's script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value policy, the user agent must monitor policy for serviceWorker.
  • +
+

+

The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).

+
+ +
+

Origin Relativity

+ +
+

Origin restriction

+ + This section is non-normative. + +

A Service worker executes in the registering service worker client's origin. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

+
+ +
+

{{WorkerGlobalScope/importScripts(urls)}}

+ +

When the importScripts(urls) method is called on a {{ServiceWorkerGlobalScope}} object, the user agent must import scripts into worker global scope, with the following options:

+ +

To validate the state, the user agent must do nothing.

+ +

To get a fetch result, the user agent must run the following steps:

+ +
    +
  1. Let serviceWorker be the settings object's global object's service worker.
  2. +
  3. If serviceWorker's imported scripts updated flag is unset, then: +
      +
    1. Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set.
    2. +
    +
  4. +
  5. Else: +
      +
    1. If there exists a corresponding Record record for url in serviceWorker's script resource map, set the script resource to record.\[[value]].
    2. +
    3. Else, set the script resource to null.
    4. +
    +
  6. +
+ +

To postprocess the fetch result, the user agent must run the following steps:

+ +
    +
  1. If serviceWorker's imported scripts updated flag is unset, then: +
      +
    1. If the fetching attempt failed (e.g. the server returned a 4xx or 5xx status code or equivalent, or there was a DNS error), throw a "{{NetworkError}}" exception and abort all these steps.
    2. +
    3. Else: +
        +
      1. If there exists a corresponding Record record for the resulting absolute URL url in serviceWorker's script resource map, set record.\[[value]] to the fetched script resource.
      2. +
      3. Else, set a newly-created Record {\[[key]]: url, \[[value]]: the fetched script resource} to serviceWorker's script resource map.
      4. +
      +
    4. +
    +
  2. +
  3. Else, if the script resource is null, throw a "{{NetworkError}}" exception and abort all these steps.
  4. +
+
+
+ +
+

Cross-Origin Resources and CORS

+ + This section is non-normative. + +

Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to fetch many sorts of off-origin resources when appropriate CORS headers are set.

+

Service workers enable this by allowing {{Cache|Caches}} to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding responses are basic filtered response, the objects stored are {{Response}} objects whose corresponding responses are either CORS filtered responses or opaque filtered responses. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding responses are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases.

+
+ +
+

Implementer Concerns

+ + This section is non-normative. + +

The implementers are encouraged to note: +

    +
  • Plug-ins should not load via service workers. As plug-ins may get their security origins from their own urls, the embedding service worker cannot handle it. For this reason, the Handle Fetch algorithm makes the potential-navigation-or-subresource request (whose context is either <embed> or <object>) immediately fallback to the network without dispatching fetch event.
  • +
  • Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with service workers.
  • +
+

+
+ +
+

Privacy

+ +

Service workers introduce new persistent storage features including scope to registration map (for service worker registrations and their service workers), request to response map and name to cache map (for caches), and script resource map (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages should be cleared when users intend to clear them and should maintain and interoperate with existing user controls e.g. purging all existing persistent storages.

+
+
+ +
+

Storage Considerations

+ +

Service workers should take a dependency on Quota Management API that extends the ServiceWorkerGlobalScope with the event listeners {{ServiceWorkerGlobalScope/onbeforeevicted}} and {{ServiceWorkerGlobalScope/onevicted}} to detect a storage pressure and give pre-eviction information to the application.

+

The cache write operations in service workers when failed due to exceeding the granted quota limit should throw "{{QuotaExceededError}}" exception.

+ + +
+

Extensibility

+ +

Service workers are extensible from other specifications.

+ +
+

Define API bound to Service Worker Registration

+ +

Specifications may define an API tied to a service worker registration by using partial interface definition to the {{ServiceWorkerRegistration}} interface where it may define the specification specific attributes and methods:

+ +
+      partial interface ServiceWorkerRegistration {
+        // e.g. define an API namespace
+        readonly attribute APISpaceType APISpace;
+        // e.g. define a method
+        Promise<T> methodName(list of arguments);
+      };
+    
+
+ +
+

Define Functional Event

+ +

Specifications may define a functional event by extending {{ExtendableEvent}} interface:

+ +
+      // e.g. define FunctionalEvent interface
+      interface FunctionalEvent : ExtendableEvent {
+        // add a functional event's own attributes and methods
+      };
+    
+
+ +
+

Define Event Handler

+ +

Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the {{ServiceWorkerGlobalScope}} interface:

+ +
+      partial interface ServiceWorkerGlobalScope {
+        attribute EventHandler onfunctionalevent;
+      };
+    
+
+ +
+

Request Functional Event Dispatch

+ +

To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

+ +

Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a {{ServiceWorkerGlobalScope}} object) at which it may fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm.

+ +

See an example hook defined in Notifications API.

+
+
+ +
+

Appendix A: Algorithms

+ +

The following definitions are the user agent's internal data structures used throughout the specification.

+ +

A scope to registration map is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a string that represents a scope url and \[[value]] is a service worker registration.

+ +

A job is an abstraction of one of register, update, and unregister request for a service worker registration.

+ +

A job has a job type, which is one of register, update, and unregister.

+ +

A job has a scope url (a URL).

+ +

A job has a script url (a URL).

+ +

A job has a worker type ("classic" or "module").

+ +

A job has a client (a service worker client). It is initially null.

+ +

A job has a promise (a promise). It is initially null.

+ +

A job has a list of equivalent job promises (a list of promises). It is initially the empty list.

+ +

A job has a force bypass cache flag It is initially unset.

+ +

Two jobs are equivalent when their job type is the same and: +

+

+ +

A job queue is a queue used to synchronize the set of concurrent jobs. The job queue contains jobs as its elements. The job queue should satisfy the general properties of FIFO queue. A user agent must maintain a separate job queue for each service worker registration keyed by its scope url. A job queue is initially empty. Unless stated otherwise, the job queue referenced from the algorithm steps is a job queue for the job's scope url.

+ +
+

Create Job

+ +
+
Input
+
jobType, a job type
+
scopeURL, a URL
+
scriptURL, a URL
+
promise, a promise
+
client, a service worker client
+
Output
+
job, a job
+
+
    +
  1. Let job be a new job.
  2. +
  3. Set job's job type to jobType.
  4. +
  5. Set job's scope url to scopeURL.
  6. +
  7. Set job's script url to scriptURL.
  8. +
  9. Set job's promise to promise.
  10. +
  11. Set job's client to client.
  12. +
  13. Return job.
  14. +
+
+ +
+

Schedule Job

+ +
+
Input
+
job, a job
+
Output
+
none
+
+
    +
  1. If the job queue is empty, then: +
      +
    1. Push job to the job queue and invoke Run Job.
    2. +
    +
  2. +
  3. Else: +
      +
    1. Let lastJob be the element at the back of the job queue.
    2. +
    3. If job is equivalent to lastJob and lastJob's promise has not settled, append job's promise to lastJob's list of equivalent job promises.
    4. +
    5. Else, push job to the job queue.
    6. +
    +
  4. +
+
+ +
+

Run Job

+ +
+
Input
+
none
+
Output
+
none
+
+
    +
  1. Assert: the job queue is not empty.
  2. +
  3. Let job be the element in the front of the job queue.
  4. +
  5. If job's job type is register, invoke Register with job and continue running these steps in parallel.
  6. +
  7. Else if job's job type is update, invoke Update with job and continue running these steps in parallel. +

    For a register job and an update job, the user agent delays invoking Register and Update respectively until after the document initiated the job has been dispatched {{Document/DOMContentLoaded}} event. If the job's client is a worker client, it is delayed until after the worker script has evaluated.

    +
  8. +
  9. Else if job's job type is unregister, invoke Unregister with job and continue running these steps in parallel.
  10. +
+
+ +
+

Finish Job

+ +
+
Input
+
job, a job
+
Output
+
none
+
+
    +
  1. Assert: the top element in the job queue is job.
  2. +
  3. Pop the top element from the job queue.
  4. +
  5. If the job queue is not empty, invoke Run Job with the top element of the job queue.
  6. +
+
+ +
+

Resolve Job Promise

+ +
+
Input
+
job, a job
+
value, any
+
Output
+
none
+
+
    +
  1. Resolve job's promise with value.
  2. +
  3. For each promise in job's list of equivalent job promises: +
      +
    1. Resolve promise with value.
    2. +
    +
  4. +
+
+ +
+

Reject Job Promise

+ +
+
Input
+
job, a job
+
reason, an exception
+
Output
+
none
+
+
    +
  1. Reject job's promise with reason.
  2. +
  3. For each promise in job's list of equivalent job promises: +
      +
    1. Reject promise with reason.
    2. +
    +
  4. +
+
+ +
+

Register

+ +
+
Input
+
job, a job
+
Output
+
promise, a promise
+
+
    +
  1. If the result of running Is origin potentially trustworthy with the origin of job's script url as the argument is Not Trusted, then: +
      +
    1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  2. +
  3. If the origin of job's script url is not job's client's origin, then: +
      +
    1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  4. +
  5. If the origin of job's scope url is not job's client's origin, then: +
      +
    1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  6. +
  7. Let registration be the result of running the Get Registration algorithm passing job's scope url as the argument.
  8. +
  9. If registration is not null, then: +
      +
    1. If registration's uninstalling flag is set, unset it.
    2. +
    3. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
    4. +
    5. If newestWorker is not null and job's script url equals newestWorker's script url, then: +
        +
      1. If newestWorker is an active worker, then: +
          +
        1. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
        2. +
        3. Invoke Finish Job with job and abort these steps.
        4. +
        +
      2. +
      +
    6. +
    +
  10. +
  11. Else: +
      +
    1. Invoke Set Registration algorithm passing job's scope url as its argument.
    2. +
    +
  12. +
  13. Invoke Update algorithm, or its equivalent, passing job as the argument.
  14. +
+
+ +
+

Update

+ +
+
Input
+
job, a job
+
Output
+
none
+
+
    +
  1. Let registration be the result of running the Get Registration algorithm passing job's scope url as the argument.
  2. +
  3. If registration is null or registration's uninstalling flag is set, then: +
      +
    1. Invoke Reject Job Promise with job and a TypeError.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  4. +
  5. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument.
  6. +
  7. If job's job type is update, and newestWorker's script url is not job's script url, then: +
      +
    1. Invoke Reject Job Promise with job and a TypeError.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  8. +
  9. Switching on job's worker type, run these substeps with the following options: +
    +
    "classic"
    +

    Fetch a classic worker script given job’s serialized script url, job’s client, and "serviceworker".

    +
    "module"
    +

    Fetch a module script tree given job’s serialized script url, "omit", "serviceworker", and job’s client.

    +
    +

    To set up the request given request, run the following steps:

    +
      +
    1. Append `Service-Worker`/`script` to request's header list. +

      See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.

      +
    2. +
    3. Set request's skip service worker flag and request's redirect mode to "error".
    4. +
    5. If newestWorker is not null and registration's last update check time is not null, then: +
        +
      1. If the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, or force bypass cache flag is set, set request's cache mode to "reload".
      2. +
      +

      Even if the cache mode is not set to "reload", the user agent obeys Cache-Control header's max-age value in the network layer to determine if it should bypass the browser cache.

      +
    6. +
    +

    To validate the response given response, run the following steps:

    +
      +
    1. Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job.
      6. +
      7. Return false and abort these steps.
      8. +
      +
    2. +
    3. Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response's header list. +

      See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.

      +
    4. +
    5. If serviceWorkerAllowed is failure, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job.
      6. +
      7. Return false and abort these steps.
      8. +
      +
    6. +
    7. Let scopeURL be registration's scope url.
    8. +
    9. Let maxScopeString be null.
    10. +
    11. If serviceWorkerAllowed is null, then: +
        +
      1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script's file name, in job's script url's path (including empty strings), separated from each other by "/".
      2. +
      +
    12. +
    13. Else: +
        +
      1. Let maxScope be the result of parsing serviceWorkerAllowed with job's script url.
      2. +
      3. Set maxScopeString to "/" concatenated with the strings in maxScope's path (including empty strings), separated from each other by "/".
      4. +
      +
    14. +
    15. Let scopeString be "/" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/".
    16. +
    17. If scopeString starts with maxScopeString, do nothing.
    18. +
    19. Else: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job.
      6. +
      7. Return false and abort these steps.
      8. +
      +
    20. +
    21. If response's cache state is not "local", set registration's last update check time to the current time.
    22. +
    23. Return true.
    24. +
    +

    If the algorithm asynchronously completes with null, then: +

      +
    1. Invoke Reject Job Promise with job and a TypeError.
    2. +
    3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
    4. +
    5. Invoke Finish Job with job and abort these steps.
    6. +
    +

    +

    Else, continue the rest of these steps after the algorithm's asynchronous completion, with script being the asynchronous completion value.

    +
  10. +
  11. If newestWorker is not null, newestWorker's script url equals job's script url with the exclude fragments flag set, and script is a byte-for-byte match with newestWorker's script resource, then: +
      +
    1. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  12. +
  13. Else: +
      +
    1. Let worker be a new service worker.
    2. +
    3. Generate a unique opaque string and set worker's id to the value.
    4. +
    5. Set worker's script url to job's script url, worker's script resource to script, and worker's type to job's worker type.
    6. +
    7. Invoke Run Service Worker algorithm with worker as the argument.
    8. +
    9. If an uncaught runtime script error occurs during the above step, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    10. +
    +
  14. +
  15. Invoke Install algorithm, or its equivalent, with job, worker, and registration as its arguments.
  16. +
+
+ +
+

Soft Update

+ +

The user agent may call this as often as it likes to check for updates.

+ +
+
Input
+
registration, a service worker registration
+
force bypass cache flag, an optional flag unset by default
+

Implementers may use the force bypass cache flag to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs.

+
Output
+
None
+
+
    +
  1. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
  2. +
  3. If newestWorker is null, abort these steps.
  4. +
  5. Let job be the result of running Create Job with update, registration's scope url, newestWorker's script url, a new promise, and null.
  6. +
  7. Set job's worker type to newestWorker's type.
  8. +
  9. Set job's force bypass cache flag if its force bypass cache flag is set.
  10. +
  11. Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job.
    2. +
    +
  12. +
+
+ +
+

Install

+ +
+
Input
+
job, a job
+
worker, a service worker
+
registration, a service worker registration
+
Output
+
none
+
+
    +
  1. Let installFailed be false.
  2. +
  3. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
  4. +
  5. Set registration's installing worker to worker.
  6. +
  7. Run the Update State algorithm passing registration's installing worker and installing as the arguments.
  8. +
  9. Assert: job's promise is not null.
  10. +
  11. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
  12. +
  13. Queue a task to fire a simple event named updatefound at all the {{ServiceWorkerRegistration}} objects for all the service worker clients whose creation url matches registration's scope url and all the service workers whose containing service worker registration is registration.
  14. +
  15. Let installingWorker be registration's installing worker.
  16. +
  17. Invoke Run Service Worker algorithm with installingWorker as the argument.
  18. +
  19. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the {{InstallEvent}} interface, with the event type install, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Dispatch e at installingWorker's environment settings object's global object globalObject.
    4. +
    5. Let extendLifetimePromises be an empty array.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
        4. +
        5. Set registration's installing worker to null.
        6. +
        7. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
        8. +
        9. Invoke Finish Job with job and abort these steps.
        10. +
        +
      2. +
      3. Let eventObject be the first argument passed to this event listener.
      4. +
      5. Append eventObject's extend lifetime promises to extendLifetimePromises.
      6. +
      +
    8. +
    9. Let p be waiting for all of extendLifetimePromises.
    10. +
    11. Run the following substeps in parallel: +
        +
      1. Wait until p settles.
      2. +
      3. If p rejected, set installFailed to true.
      4. +
      5. Else if p resolved with a value, do nothing.
      6. +
      +
    12. +
    +
  20. +

    If task is discarded or the script has been aborted by the termination of installingWorker, set installFailed to true.

    +
  21. Wait for task to have executed or been discarded.
  22. +
  23. If installFailed is true, then: +
      +
    1. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    2. +
    3. Set registration's installing worker to null.
    4. +
    5. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
    6. +
    7. Invoke Finish Job with job and abort these steps.
    8. +
    +
  24. +
  25. Set registration's installing worker's imported scripts updated flag.
  26. +
  27. If registration's waiting worker is not null, then: +
      +
    1. Terminate registration's waiting worker.
    2. +
    3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
    4. +
    5. The user agent may abort in-flight requests triggered by registration's waiting worker.
    6. +
    +
  28. +
  29. Set registration's waiting worker to registration's installing worker.
  30. +
  31. Set registration's installing worker to null.
  32. +
  33. Run the Update State algorithm passing registration's waiting worker and installed as the arguments.
  34. +
  35. If registration's waiting worker's skip waiting flag is set, then: +
      +
    1. Run Activate algorithm, or its equivalent, passing registration as the argument.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  36. +
  37. Invoke Finish Job with job.
  38. +
  39. Wait for all the tasks queued by Update State invoked in this algorithm have executed.
  40. +
  41. Wait until no service worker client is using registration or registration's waiting worker's skip waiting flag is set.
  42. +
  43. If registration's waiting worker waitingWorker is not null and waitingWorker's skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument.
  44. +
+
+ +
+

Activate

+ +
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Let activatingWorker be registration's waiting worker.
  2. +
  3. Let exitingWorker be registration's active worker.
  4. +
  5. If activatingWorker is null, abort these steps.
  6. +
  7. If exitingWorker is not null, then: +
      +
    1. Wait for exitingWorker to finish handling any in-progress requests. +
    2. +
    3. Terminate exitingWorker.
    4. +
    5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
    6. +
    +
  8. +
  9. Set registration's active worker to activatingWorker.
  10. +
  11. Set registration's waiting worker to null.
  12. +
  13. Run the Update State algorithm passing registration's active worker and activating as the arguments. +

    Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated.

    +
  14. +
  15. For each service worker client client whose creation url matches registration's scope url: +
      +
    1. If client is a window client, unassociate client's responsible document from its application cache, if it has one.
    2. +
    3. Else if client is a shared worker client, unassociate client's global object from its application cache, if it has one.
    4. +
    +

    Resources will now use the service worker registration instead of the existing application cache.

    +
  16. +
  17. For each service worker client client who is using registration: +
      +
    1. Set client's active worker to registration's active worker.
    2. +
    3. Invoke Notify Controller Change algorithm with client as the argument.
    4. +
    +
  18. +
  19. Let activeWorker be registration's active worker.
  20. +
  21. Invoke Run Service Worker algorithm with activeWorker as the argument.
  22. +
  23. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the {{ExtendableEvent}} interface, with the event type activate, which does not bubble, is not cancelable, and has no default action.
    2. +
    3. Dispatch e at activeWorker's environment settings object's global object.
    4. +
    5. Let extendLifetimePromises be an empty array.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, report the error for the script per the runtime script errors handling.
      2. +
      3. Let eventObject be the first argument passed to this event listener.
      4. +
      5. Append eventObject's extend lifetime promises to extendLifetimePromises.
      6. +
      +
    8. +
    9. Let p be waiting for all of extendLifetimePromises.
    10. +
    +
  24. +
  25. Wait for task to have executed and p defined in task has settled, or task to have been discarded or the script to have been aborted by the termination of activeWorker.
  26. +
  27. Run the Update State algorithm passing registration's active worker and activated as the arguments.
  28. +
+
+ +
+

Run Service Worker

+ +
+
Input
+
serviceWorker, a service worker
+
Output
+
None
+
+
    +
  1. Let script be serviceWorker's script resource.
  2. +
  3. Assert: script is not null.
  4. +
  5. If serviceWorker is already running, abort these steps.
  6. +
  7. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.
  8. +
  9. Call the JavaScript InitializeHostDefinedRealm() abstract operation with the following customizations: +
      +
    • For the global object, create a new {{ServiceWorkerGlobalScope}} object. Let workerGlobalScope be the created object.
    • +
    • Let realmExecutionContext be the created JavaScript execution context.
    • +
    +
  10. +
  11. Let workerEventLoop be a newly created event loop.
  12. +
  13. Let workerGlobalScope be realmExecutionContext's global object.
  14. +
  15. Let settingsObject be a new environment settings object whose algorithms are defined as follows: +
    +
    The realm execution context
    +
    Return realmExecutionContext.
    +
    The global object
    +
    Return workerGlobalScope.
    +
    The responsible event loop
    +
    Return workerEventLoop.
    +
    The referrer source
    +
    Return serviceWorker's script url.
    +

    Remove this definition after sorting out the referencing sites.

    +
    The API URL character encoding
    +
    Return UTF-8.
    +
    The API base URL
    +
    Return serviceWorker's script url.
    +
    The origin and effective script origin
    +
    Return its registering service worker client's origin.
    +
    The creation URL
    +
    Return workerGlobalScope's url.
    +
    The HTTPS state
    +
    Return workerGlobalScope's HTTPS state.
    +
    +
  16. +
  17. Set workerGlobalScope's url to serviceWorker's script url.
  18. +
  19. Set workerGlobalScope's HTTPS state to serviceWorker's script resource's HTTPS state.
  20. +
  21. Set workerGlobalScope's type to serviceWorker's type.
  22. +
  23. Create a new {{WorkerLocation}} object and associate it with workerGlobalScope.
  24. +
  25. If serviceWorker is an active worker, and there are any tasks queued in serviceWorker's containing service worker registration's task queues, queue them to serviceWorker's event loop's task queues in the same order using their original task sources.
  26. +
  27. If script is a classic script, then run the classic script script. Otherwise, it is a module script; run the module script script. +

    In addition to the usual possibilities of returning a value or failing due to an exception, this could be prematurely aborted by the kill a worker or terminate a worker algorithms.

    +
  28. +
  29. If script's has ever been evaluated flag is unset, then: +
      +
    1. Set workerGlobalScope's associated service worker's set of event types to handle to the set of event types created from settingsObject's global object's associated list of event listeners' event types. +

      If the global object's associated list of event listeners does not have any event listener added at this moment, the service worker's set of event types to handle is set to an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script.

      +
    2. +
    3. Set script's has ever been evaluated flag.
    4. +
    +
  30. +
  31. Run the responsible event loop specified by settingsObject until it is destroyed.
  32. +
  33. Empty workerGlobalScope's list of active timers.
  34. +
+
+ +
+

Terminate Service Worker

+ +
+
Input
+
serviceWorker, a service worker
+
Output
+
None
+
+
    +
  1. If serviceWorker is not running, abort these steps.
  2. +
  3. Let serviceWorkerGlobalScope be serviceWorker environment settings object's global object.
  4. +
  5. Set serviceWorkerGlobalScope's closing flag to true.
  6. +
  7. If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in serviceWorkerGlobalScope's event loop's task queues, queue them to serviceWorker's containing service worker registration's corresponding task queues in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from serviceWorkerGlobalScope's event loop's task queues without processing them. +

    This effectively means that the fetch events and the other functional events such as push events are backed up by the registration's task queues while the other tasks including message events are discarded.

    +
  8. +
  9. Abort the script currently running in serviceWorker.
  10. +
+
+ +
+

Handle Fetch

+ +

The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

+ +
+
Input
+
request, a request
+
Output
+
response, a response
+
+
    +
  1. Let handleFetchFailed be false.
  2. +
  3. Let respondWithEntered be false.
  4. +
  5. Let eventCanceled be false.
  6. +
  7. Let r be a new {{Request}} object associated with request.
  8. +
  9. Let headersObject be r's {{Request/headers}} attribute value.
  10. +
  11. Set headersObject's guard to immutable.
  12. +
  13. Let response be null.
  14. +
  15. Let registration be null.
  16. +
  17. Let client be the service worker client that corresponds to request's client.
  18. +
  19. Assert: request's destination is not "serviceworker".
  20. +
  21. If request is a potential-navigation-or-subresource request, then: +
      +
    1. Return null.
    2. +
    +
  22. +
  23. Else if request is a non-subresource request, then: +

    If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration.

    +
      +
    1. If client is not a secure context, return null.
    2. +
    3. If request is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null.
    4. +
    5. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing request's url as the argument.
    6. +
    7. If registration is null or registration's active worker is null, return null.
    8. +
    9. Set client's active worker to registration's active worker.
    10. +
    +

    From this point, the service worker client starts to use its active worker's containing service worker registration.

    +
  24. +
  25. Else if request is a subresource request, then: +
      +
    1. If client's active worker is non-null, set registration to client's active worker's containing service worker registration.
    2. +
    3. Else, return null.
    4. +
    +
  26. +
  27. Let activeWorker be registration's active worker.
  28. +
  29. If activeWorker's set of event types to handle does not contain fetch, return null. +

    To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.

    +
  30. +
  31. If activeWorker's state is activating, wait for activeWorker's state to become activated.
  32. +
  33. Invoke Run Service Worker algorithm with activeWorker as the argument.
  34. +
  35. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the {{FetchEvent}} interface, with the event type fetch, which does not bubble and has no default action.
    2. +
    3. Let the request attribute of e be initialized to r.
    4. +
    5. Let the clientId attribute of e be initialized to client's id if request is not a non-subresource request, and to null otherwise.
    6. +
    7. Let the isReload attribute of e be initialized to true if request's client is a window client and the event was dispatched with the user's intention for the page reload, and false otherwise.
    8. +
    9. Dispatch e at activeWorker's environment settings object's global object.
    10. +
    11. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      3. Let event be the event for which this event listener was invoked.
      4. +
      5. If event's respond-with entered flag is set, set respondWithEntered to true.
      6. +
      7. If event's wait to respond flag is set, then: +
          +
        1. Wait until event's wait to respond flag is unset.
        2. +
        3. If event's respond-with error flag is set, set handleFetchFailed to true.
        4. +
        5. Else, set response to event's potential response.
        6. +
        +
      8. +
      9. If event's canceled flag is set, set eventCanceled to true.
      10. +
      +
    12. +
    +

    If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

    +

    The task must use activeWorker's event loop and the handle fetch task source.

    +
  36. +
  37. Wait for task to have executed or been discarded.
  38. +
  39. If respondWithEntered is false, then: +
      +
    1. If eventCanceled is true, return a network error and continue running these substeps in parallel.
    2. +
    3. Else, return null and continue running these substeps in parallel.
    4. +
    5. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
    6. +
    7. Abort these steps.
    8. +
    +
  40. +
  41. If handleFetchFailed is true, then: +
      +
    1. Return a network error and continue running these substeps in parallel.
    2. +
    3. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
    4. +
    +
  42. +
  43. Else: +
      +
    1. Return response and continue running these substeps in parallel.
    2. +
    3. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
    4. +
    +
  44. +
+
+ +
+

Handle Foreign Fetch

+ +

The [[#on-foreign-fetch-request-algorithm]] algorithm is the entry point for the fetch handling handed to the service worker context to handle foreign fetch requests.

+ +

This needs an extra step in the HTTP fetch algorithm in between step 3 and 4, to call this algorithm for all requests if response is null at that point.

+ +
+
Input
+
request, a request
+
Output
+
response, a response
+
+
    +
  1. Let handleFetchFailed be false.
  2. +
  3. Let respondWithEntered be false.
  4. +
  5. Let eventCanceled be false.
  6. +
  7. If request is not a subresource request, return null and abort these steps. +

    Foreign fetch only allows intercepting of subresource requests. Navigation requests can be intercepted by the regular fetch event anyway, so there is no benefit to supporting those requests here as well.

    +
  8. +
  9. If request's client is not a secure context, return null and abort these steps.
  10. +
  11. Let activeWorker be the result of running the [[#foreign-fetch-scope-match-algorithm]] algorithm passing request's url as the argument.
  12. +
  13. If activeWorker is null, return null.
  14. +
  15. If activeWorker's state is activating, then: +
      +
    1. Wait for activeWorker's state to become activated.
    2. +
    +
  16. +
  17. If activeWorker's origin is the same as request's origin, return null.
  18. +
  19. Let originMatches be false.
  20. +
  21. If activeWorker's list of foreign fetch origins is empty, set originMatches to true.
  22. +
  23. For each origin in activeWorker's list of foreign fetch origins: +
      +
    1. If origin is equal to request's origin, set originMatches to true.
    2. +
    +
  24. +
  25. If originMatches is false, return null.
  26. +
  27. Let r be a new {{Request}} object associated with request.
  28. +
  29. Invoke [[#run-service-worker-algorithm]] algorithm with activeWorker as the argument.
  30. +
  31. Queue a task task to run the following substeps: +
      +
    1. Create a trusted event e that uses the {{ForeignFetchEvent}} interface, with the event type foreignfetch, which does not bubble and has no default action.
    2. +
    3. Let the {{FetchEvent/request}} attribute of e be initialized to r.
    4. +
    5. Dispatch e at activeWorker's environment settings object's global object.
    6. +
    7. For each event listener invoked: +
        +
      1. If any uncaught runtime script error occurs, then: +
          +
        1. Report the error for the script per the runtime script errors handling.
        2. +
        3. Abort these steps.
        4. +
        +
      2. +
      3. Let event be the event for which this event listener was invoked.
      4. +
      5. If event's respond-with entered flag is set, then: +
          +
        1. Set respondWithEntered to true.
        2. +
        +
      6. +
      7. If event's wait to respond flag is set, then: +
          +
        1. Wait until event's wait to respond flag is unset.
        2. +
        +
      8. +
      9. Let internalResponse be event's potential response.
      10. +
      11. If internalResponse is a filtered response, set internalResponse to internalResponse's internal response.
      12. +
      13. If event's respond-with error flag is set, set handleFetchFailed to true.
      14. +
      15. Else if event's origin is null: +
          +
        1. If event's list of exposed headers is not empty, set handleFetchFailed to true.
        2. +
        3. Else if event's potential response is a opaque-redirect filtered response, set response to event's potential response.
        4. +
        5. Else set response to an opaque filtered response of internalResponse.
        6. +
        +
      16. +
      17. Else if event's origin is not equal to request's origin, set handleFetchFailed to true.
      18. +
      19. Else if event's potential response is an opaque filtered response or is an opaque-redirect filtered response, set response to event's potential response.
      20. +
      21. Else if request's response tainting is "opaque", set response to an opaque filtered response of internalResponse.
      22. +
      23. Else: +
          +
        1. Let headers be event's list of exposed headers.
        2. +
        3. If response is a CORS filtered response, remove from internalResponse's CORS-exposed header-names list all values not in headers.
        4. +
        5. Else set internalResponse's CORS-exposed header-names list to headers.
        6. +
        7. Set response to a CORS filtered response of internalResponse.
        8. +
        +
      24. +
      25. If event's canceled flag is set, then: +
          +
        1. Set eventCanceled to true.
        2. +
        +
      26. +
      +
    8. +
    +

    If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

    +

    The task must use activeWorker's event loop and the handle fetch task source.

    +
  32. +
  33. Wait for task to have executed or been discarded.
  34. +
  35. If respondWithEntered is false, then: +
      +
    1. If eventCanceled is true, then: +
        +
      1. Return a network error.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Return null.
      2. +
      +
    4. +
    +
  36. +
  37. If handleFetchFailed is true, then: +
      +
    1. Return a network error.
    2. +
    +
  38. +
  39. Else: +
      +
    1. Return response.
    2. +
    +
  40. +
+
+ +
+

Handle Functional Event

+ +
+
Input
+
registration, a service worker registration
+
callbackSteps, an algorithm
+
Output
+
None
+
+
    +
  1. Assert: a Record with the \[[value]] equals to registration is contained in scope to registration map.
  2. +
  3. Assert: registration's active worker is not null.
  4. +
  5. Let activeWorker be registration's active worker.
  6. +
  7. If activeWorker's set of event types to handle does not contain the event type for this functional event, return. +

    To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.

    +
  8. +
  9. If activeWorker's state is activating, wait for activeWorker's state to become activated.
  10. +
  11. Invoke Run Service Worker algorithm with activeWorker as the argument.
  12. +
  13. Queue a task task to invoke callbackSteps with activeWorker's environment settings object's global object as its argument. +

    The task must use activeWorker's event loop and the handle functional event task source.

    +
  14. +
  15. Wait for task to have executed or been discarded.
  16. +
  17. If the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
  18. +
+
+ +
+

Handle Service Worker Client Unload

+ +

The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

+ +
+
Input
+
client, a service worker client
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be the service worker registration used by client.
  4. +
  5. If registration is null, abort these steps.
  6. +
  7. If any other service worker client is using registration, abort these steps.
  8. +
  9. If registration's uninstalling flag is set, invoke Clear Registration algorithm passing registration as its argument and abort these steps.
  10. +
  11. If registration's waiting worker is not null, run Activate algorithm, or its equivalent, with registration as the argument.
  12. +
+
+ +
+

Handle User Agent Shutdown

+ +
+
Input
+
None
+
Output
+
None
+
+
    +
  1. For each Record {\[[key]], \[[value]]} entry of its scope to registration map: +
      +
    1. Let registration be entry.\[[value]].
    2. +
    3. If registration's installing worker installingWorker is not null, then: +
        +
      1. If the result of running Get Newest Worker with registration is installingWorker, invoke Clear Registration with registration and continue to the next iteration of the loop.
      2. +
      3. Else, set registration's installing worker to null.
      4. +
      +
    4. +
    5. If registration's waiting worker is not null, run the following substep in parallel: +
        +
      1. Invoke Activate with registration.
      2. +
      +
    6. +
    +
  2. +
+
+ +
+

Unregister

+ +
+
Input
+
job, a job
+
Output
+
none
+
+
    +
  1. If the origin of job's scope url is not job's client's origin, then: +
      +
    1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  2. +
  3. Let registration be the result of running Get Registration algorithm passing job's scope url as the argument.
  4. +
  5. If registration is null, then: +
      +
    1. Invoke Resolve Job Promise with job and false.
    2. +
    3. Invoke Finish Job with job and abort these steps.
    4. +
    +
  6. +
  7. Set registration's uninstalling flag.
  8. +
  9. Invoke Resolve Job Promise with job and true.
  10. +
  11. If no service worker client is using registration, then: +
      +
    1. If registration's uninstalling flag is unset, invoke Finish Job with job and abort these steps.
    2. +
    3. Invoke Clear Registration algorithm passing registration as its argument.
    4. +
    +

    When the registration is being used for a client, the deletion of the registration is handled by the Handle Service Worker Client Unload algorithm.

    +
  12. +
  13. Invoke Finish Job with job.
  14. +
+
+ +
+

Set Registration

+ +
+
Input
+
scope, a URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let scopeString be serialized scope with the exclude fragment flag set.
  4. +
  5. Let registration be a new service worker registration whose scope url is set to scope.
  6. +
  7. Set a newly-created Record {\[[key]]: scopeString, \[[value]]: registration} to scope to registration map.
  8. +
  9. Return registration.
  10. +
+
+ +
+

Clear Registration

+ +
+
Input
+
registration, a service worker registration
+
Output
+
None
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. If registration's installing worker is not null, then: +
      +
    1. Terminate registration's installing worker.
    2. +
    3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
    4. +
    5. Set registration's installing worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's installing worker.
    8. +
    +
  4. +
  5. If registration's waiting worker is not null, then: +
      +
    1. Terminate registration's waiting worker.
    2. +
    3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
    4. +
    5. Set registration's waiting worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's waiting worker.
    8. +
    +
  6. +
  7. If registration's active worker is not null, then: +
      +
    1. Terminate registration's active worker.
    2. +
    3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
    4. +
    5. Set registration's active worker to null.
    6. +
    7. The user agent may abort in-flight requests triggered by registration's active worker.
    8. +
    +
  8. +
  9. Delete a Record {\[[key]], \[[value]]} entry from scope to registration map where registration's scope url is the result of parsing entry.\[[key]].
  10. +
+
+ +
+

Update State

+ +
+
Input
+
worker, a service worker
+
state, a service worker's state
+
Output
+
None
+
+
    +
  1. Set worker's state to state.
  2. +
  3. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker.
  4. +
  5. For each serviceWorker in serviceWorkers: +
      +
    1. Queue a task to fire a simple event named statechange at serviceWorker.
    2. +
    +

    The task must use serviceWorker's relevant settings object's responsible event loop and the DOM manipulation task source.

    +
  6. +
+
+ +
+

Notify Controller Change

+ +
+
Input
+
client, a service worker client
+
Output
+
None
+
+
    +
  1. Assert: client is not null.
  2. +
  3. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with.
  4. +
+

The task must use client's responsible event loop and the DOM manipulation task source.

+
+ +
+

Match Service Worker Registration

+ +
+
Input
+
clientURL, a URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let clientURLString be serialized clientURL.
  4. +
  5. Let matchingScope be the empty string.
  6. +
  7. Set matchingScope to the longest \[[key]] in scope to registration map which the value of clientURLString starts with, if it exists. +

    The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix").

    +
  8. +
  9. Let parsedMatchingScope be null.
  10. +
  11. If matchingScope is not the empty string, set parsedMatchingScope to the result of parsing matchingScope.
  12. +
  13. Let registration be the result of running Get Registration algorithm passing parsedMatchingScope as the argument.
  14. +
  15. If registration is not null and registration's uninstalling flag is set, return null.
  16. +
  17. Return registration.
  18. +
+
+ +
+

Match Service Worker for Foreign Fetch

+ +
+
Input
+
requestURL, a URL
+
Output
+
worker, a service worker
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let registration be the result of running the [[#scope-match-algorithm]] algorithm passing requestURL as the argument.
  4. +
  5. If registration is null, return null.
  6. +
  7. Let worker be registration's active worker.
  8. +
  9. If worker is null, return null.
  10. +
  11. Let requestURLString be the serialized requestURL.
  12. +
  13. For each URL scope in worker's list of foreign fetch scopes: +
      +
    1. Let scopeString be the serialized scope.
    2. +
    3. If requestString starts with scopeString return worker.
    4. +
    +
  14. +
  15. Return null.
  16. +
+
+ +
+

Get Registration

+ +
+
Input
+
scope, a URL
+
Output
+
registration, a service worker registration
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let scopeString be the empty string.
  4. +
  5. If scope is not null, set scopeString to serialized scope with the exclude fragment flag set.
  6. +
  7. Let registration be null.
  8. +
  9. For each Record {\[[key]], \[[value]]} entry of its scope to registration map: +
      +
    1. If scopeString matches entry.\[[key]], set registration to entry.\[[value]].
    2. +
    +
  10. +
  11. Return registration.
  12. +
+
+ +
+

Get Newest Worker

+ +
+
Input
+
registration, a service worker registration
+
Output
+
worker, a service worker
+
+
    +
  1. Run the following steps atomically.
  2. +
  3. Let newestWorker be null.
  4. +
  5. If registration's installing worker is not null, set newestWorker to registration's installing worker.
  6. +
  7. Else if registration's waiting worker is not null, set newestWorker to registration's waiting worker.
  8. +
  9. Else if registration's active worker is not null, set newestWorker to registration's active worker.
  10. +
  11. Return newestWorker.
  12. +
+
+ +
+

Create Client

+ +
+
Input
+
client, a service worker client
+
Output
+
clientObject, a {{Client}} object
+
+
    +
  1. Let clientObject be a new {{Client}} object.
  2. +
  3. Set clientObject's service worker client to client.
  4. +
  5. Return clientObject.
  6. +
+
+ +
+

Create Window Client

+ +
+
Input
+
client, a service worker client
+
visibilityState, a string
+
focusState, a boolean
+
Output
+
windowClient, a {{WindowClient}} object
+
+
    +
  1. Let windowClient be a new {{WindowClient}} object.
  2. +
  3. Set windowClient's service worker client to client.
  4. +
  5. Set windowClient's visibility state to visibilityState.
  6. +
  7. Set windowClient's focus state to focusState.
  8. +
  9. Return windowClient.
  10. +
+
+ +
+

Query Cache

+ +
+
Input
+
request, a {{Request}} object
+
options, a {{CacheQueryOptions}} object, optional
+
targetStorage, an array that has [{{Request}}, {{Response}}] pairs as its elements, optional
+
Output
+
resultArray, an array that has [{{Request}}, {{Response}}] pairs as its elements
+
+
    +
  1. Let requestArray be an empty array.
  2. +
  3. Let responseArray be an empty array.
  4. +
  5. Let resultArray be an empty array.
  6. +
  7. If options.{{CacheQueryOptions/ignoreMethod}} is false and request.method is neither "GET" nor "HEAD", return resultArray.
  8. +
  9. Let cachedURL and requestURL be null.
  10. +
  11. Let serializedCachedURL and serializedRequestURL be null.
  12. +
  13. If the optional argument targetStorage is omitted, then: +
      +
    1. For each fetching record entry of its request to response map, in key insertion order: +
        +
      1. Set cachedURL to entry.\[[key]]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.ignoreSearch is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add a copy of entry.\[[key]] to requestArray.
        2. +
        3. Add a copy of entry.\[[value]] to responseArray.
        4. +
        +
      12. +
      +
    2. +
    +
  14. +
  15. Else: +
      +
    1. For each record in targetStorage: +
        +
      1. Set cachedURL to record[0]'s associated request's url.
      2. +
      3. Set requestURL to request's associated request's url.
      4. +
      5. If options.{{CacheQueryOptions/ignoreSearch}} is true, then: +
          +
        1. Set cachedURL's query to the empty string.
        2. +
        3. Set requestURL's query to the empty string.
        4. +
        +
      6. +
      7. Set serializedCachedURL to serialized cachedURL.
      8. +
      9. Set serializedRequestURL to serialized requestURL.
      10. +
      11. If serializedCachedURL matches serializedRequestURL, then: +
          +
        1. Add record[0] to requestArray.
        2. +
        3. Add record[1] to responseArray.
        4. +
        +
      12. +
      +
    2. +
    +
  16. +
  17. For each cachedResponse in responseArray with the index index: +
      +
    1. Let cachedRequest be the indexth element in requestArray.
    2. +
    3. If cachedResponse's response's header list contains no header named `Vary`, or options.{{CacheQueryOptions/ignoreVary}} is true, then: +
        +
      1. Add an array [cachedRequest, cachedResponse] to resultArray.
      2. +
      3. Continue to the next iteration of the loop.
      4. +
      +
    4. +
    5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
    6. +
    7. Let matchFailed be false.
    8. +
    9. For each f in varyHeaders: +
        +
      1. If f matches "*", or the result of running cachedRequest.{{Request/headers}} object's {{Headers/get(name)}} method with f as the argument does not match the result of running request.{{Request/headers}} object's {{Headers/get(name)}} method with f as the argument, then: +
          +
        1. Set matchFailed to true.
        2. +
        3. Break the loop.
        4. +
        +
      2. +
      +
    10. +
    11. If matchFailed is false, add an array [cachedRequest, cachedResponse] to resultArray.
    12. +
    +
  18. +
  19. Return resultArray.
  20. +
+
+ +
+

Batch Cache Operations

+ +
+
Input
+
operations, an array of {{CacheBatchOperation}} dictionary objects
+
Output
+
promise, a promise resolves with an array of {{Response}} objects.
+
+
    +
  1. Let p be a promise resolved with no value.
  2. +
  3. Return the result of transforming p with a fulfillment handler that performs the following substeps in parallel: +
      +
    1. Let itemsCopy be a new request to response map that is a copy of its context object's request to response map.
    2. +
    3. Let addedRecords be an empty array.
    4. +
    5. Try running the following substeps atomically: +
        +
      1. Let resultArray be an empty array.
      2. +
      3. For each operation in operations with the index index: +
          +
        1. If operation.{{CacheBatchOperation/type}} matches neither "delete" nor "put", throw a TypeError.
        2. +
        3. If operation.{{CacheBatchOperation/type}} matches "delete" and operation.{{CacheBatchOperation/response}} is not null, throw a TypeError.
        4. +
        5. If the result of running Query Cache algorithm passing operation.{{CacheBatchOperation/request}}, operation.{{CacheBatchOperation/options}}, and addedRecords as the arguments is not an empty array, throw an "{{InvalidStateError}}" exception.
        6. +
        7. Let requestResponseArray be the result of running Query Cache algorithm passing operation.{{CacheBatchOperation/request}} and operation.{{CacheBatchOperation/options}} as the arguments.
        8. +
        9. For each requestResponse in requestResponseArray: +
            +
          1. If operation.{{CacheBatchOperation/type}} matches "delete", remove the corresponding fetching record from request to response map.
          2. +
          +
        10. +
        11. If operation.{{CacheBatchOperation/type}} matches "put", then: +
            +
          1. If operation.{{CacheBatchOperation/response}} is null, throw a TypeError.
          2. +
          3. Let r be operation.{{CacheBatchOperation/request}}'s associated request.
          4. +
          5. If r's url's scheme is not one of "http" and "https", throw a TypeError.
          6. +
          7. If r's method is not `GET`, throw a TypeError.
          8. +
          9. If operation.{{CacheBatchOperation/options}} is not null, throw a TypeError.
          10. +
          11. If there exists a corresponding fetching record fetchingRecord for operation.{{CacheBatchOperation/request}} and operation.{{CacheBatchOperation/response}} in request to response map, set fetchingRecord.\[[value]] to operation.{{CacheBatchOperation/response}}.
          12. +
          13. Else, set a newly-created fetching record {\[[key]]: operation.{{CacheBatchOperation/request}}, \[[value]]: operation.{{CacheBatchOperation/response}}} to request to response map. +

            The cache commit is allowed as long as the response's headers are available.

            +
          14. +
          15. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "{{QuotaExceededError}}" exception.
          16. +
          17. Add an array [operation.request, operation.response] to addedRecords.
          18. +
          +
        12. +
        13. Add operation.response to resultArray.
        14. +
        +
      4. +
      5. Return resultArray.
      6. +
      +
    6. +
    7. And then, if an exception was thrown, then: +
        +
      1. Set the context object's request to response map to itemsCopy.
      2. +
      3. Throw the exception
      4. +
      +
    8. +
    +
  4. +
+
+
+ +
+

Appendix B: Extended HTTP headers

+ +
+

Service Worker Script Request

+ +

An HTTP request to fetch a service worker's script resource will include the following header:

+ +
+
`Service-Worker`
+
Indicates this request is a service worker's script resource request. +

This header helps administrators log the requests and detect threats.

+
+
+
+ +
+

Service Worker Script Response

+ +

An HTTP response to a service worker's script resource request can include the following header:

+ +
+
`Service-Worker-Allowed`
+
Indicates the user agent will override the path restriction, which limits the maximum allowed scope url that the script can control, to the given value. +

The value is a URL. If a relative URL is given, it is parsed against the script's URL.

+
+
+ +
+ Default scope: + +
+// Maximum allowed scope defaults to the path the script sits in
+// "/js" in this example
+navigator.serviceWorker.register("/js/sw.js").then(function() {
+  console.log("Install succeeded with the default scope '/js'.");
+});
+      
+
+ +
+ Upper path without Service-Worker-Allowed header: + +
+// Set the scope to an upper path of the script location
+// Response has no Service-Worker-Allowed header
+navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(function() {
+  console.error("Install failed due to the path restriction violation.");
+});
+      
+
+ +
+ Upper path with Service-Worker-Allowed header: + +
+// Set the scope to an upper path of the script location
+// Response included "Service-Worker-Allowed : /"
+navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(function() {
+  console.log("Install succeeded as the max allowed scope was overriden to '/'.");
+});
+      
+
+ +
+ A path restriction voliation even with Service-Worker-Allowed header: + +
+// Set the scope to an upper path of the script location
+// Response included "Service-Worker-Allowed : /foo"
+navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(function() {
+  console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
+});
+      
+
+
+ +
+

Syntax

+ +

ABNF for the values of the headers used by the service worker's script resource requests and responses:

+ +
+    Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
+    
+ +

The validation of the Service-Worker-Allowed header's values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.

+
+
+ +
+

Acknowledgements

+ +

Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

+ +

Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.

+ +

In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref and Jinho Bang.

+ +

Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

+ +

The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

+ +

Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.

+
diff --git a/spec/service_worker/index.html b/spec/service_worker/index.html index 214326e4..065b4f17 100644 --- a/spec/service_worker/index.html +++ b/spec/service_worker/index.html @@ -1,3136 +1,6231 @@ - - - - Service Workers - - - - - - - - - - -
- - - - - -

Introduction

- - -

About this Document

- -

All diagrams, examples, notes, are non-normative, as well as sections explicitly marked as non-normative. Everything else in this specification is normative.

- -

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification.

- -

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementers, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

-
- - -

Dependencies

- -

This document relies on the following specifications:

- - -
- - -

Motivations

- +

Abstract

+
+

This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.

+

The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.

+

The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.

+
+

Status of this document

+
+

This is a public copy of the editors’ draft. + It is provided for discussion only and may change at any moment. + Its publication here does not imply endorsement of its contents by W3C. + Don’t cite this document other than as work in progress.

+

Changes to this document may be tracked at https://github.com/slightlyoff/ServiceWorker.

+

The (archived) public mailing list public-webapps@w3.org (see instructions) + is preferred for discussion of this specification. + When sending e-mail, + please put the text “service-workers” in the subject, + preferably like this: + “[service-workers] …summary of comment…

+

This document was produced by the Web Platform Working Group.

+

This document was produced by a group operating under + the 5 February 2004 W3C Patent Policy. + W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; + that page also includes instructions for disclosing a patent. + An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

+

This document is governed by the 1 September 2015 W3C Process Document.

+

+

This is a living document addressing new features including foreign fetch and header-based installation, etc. Readers need to be aware that this specification includes unstable features. Implementers interested in implementing this specification should refer to the latest TR of Service Workers 1 instead.

+
+
+ +
+
+

1. Motivations

+

This section is non-normative.

Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

- -

The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may over-ride default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

- -

Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

- -

Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

- -

service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

- -

service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

- - - - -

Model

- - -

Service Worker

-

A service worker is a type of web worker. A service worker executes in the registering service worker client's origin.

-

A service worker has an associated state, which is one of parsed, installing, installed, activating, activated, and redundant. (Initially parsed).

-

A service worker has an associated script url (a URL).

-

A service worker has an associated containing service worker registration (a service worker registration), which contains itself.

-

A service worker is dispatched a set of lifecycle events, install and activate, and functional events including fetch.

-

A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.

- - -

Lifetime

-

The lifetime of a service worker is tied to the execution lifetime of events, not references held by service worker clients to the ServiceWorker object. The user agent may terminate service workers at any time it has no event to handle or detects abnormal operation such as infinite loops and tasks exceeding imposed time limits, if any, while handling the events.

-
-
- - -

Service Worker Registration

-

A service worker registration is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. The user agents may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

-

A service worker registration has an associated scope url (a URL).

-

A service worker registration has an associated registering script url (a URL).

-

A service worker registration has an associated installing worker (a service worker) whose state is installing. It is initially set to null.

-

A service worker registration has an associated waiting worker (a service worker) whose state is installed. It is initially set to null.

-

A service worker registration has an associated active worker (a service worker) whose state is either activating or activated. It is initially set to null. An active worker controls a service worker client if the active worker's containing service worker registration's scope url matches the service worker client's creation url upon navigation. When a service worker client is controlled by an active worker, it is considered the service worker client is using the active worker's containing service worker registration.

-

A service worker registration has an associated uninstalling flag. It is initially unset.

- - -

Lifetime

-

The user agents must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. The user agent has a scope to registration map that stores the entries of the tuple of service worker registration's scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

-
-
- -

Service Worker Client

-

A service worker client is an environment settings object that specifies various settings for its JavaScript global environment. A service worker client independently selects and uses a service worker registration for its own loading and its subresources.

- -

A service worker client has an associated active worker (an active worker) which currently controls it. It is initially set to null.

- -

A window client is a service worker client whose global object is a Window object.

- -

A dedicated worker client is a service worker client whose global object is a DedicatedWorkerGlobalObject object.

- -

A shared worker client is a service worker client whose global object is a SharedWorkerGlobalObject object.

- -

A worker client is either a dedicated worker client or a shared worker client.

-
-
- - -

Client Context

- -

Example: Bootstrapping with a ServiceWorker

- -// scope defaults to "/" -navigator.serviceWorker.register("/assets/v1/serviceworker.js").then( - function(registration) { - console.log("success!"); - if (registration.installing) { - registration.installing.postMessage("Howdy from your installing page."); - } - }, - function(why) { - console.error("Installing the worker failed!:", why); - }); - - -

ServiceWorker

- -

-[Exposed=(Window,Worker)] -interface ServiceWorker : Worker { - readonly attribute USVString scriptURL; - readonly attribute ServiceWorkerState state; +

The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

+

Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

+

Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

+

Service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

+

Service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

+
+
+

2. Model

+
+

2.1. Service Worker

+

A service worker#dfn-service-workerReferenced in:1. Motivations (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)2.1. Service Worker (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)2.1.1. Lifetime (2)2.2. Service Worker Registration (2) (3) (4)2.5. Task Sources (2) (3)2.6. User Agent Shutdown3.1. ServiceWorker (2) (3) (4)3.1.1. scriptURL3.1.2. state (2) (3) (4) (5) (6) (7) (8) (9)3.1.3. postMessage(message, transfer)3.2.1. installing3.2.2. waiting3.2.3. active3.4. ServiceWorkerContainer3.4.1. controller3.5. ServiceWorkerMessageEvent (2)3.5.2. event.origin3.5.4. event.source3.6. Events (2) (3)4.1. ServiceWorkerGlobalScope (2) (3) (4)4.1.3. skipWaiting() (2) (3) (4)4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f) (2) (3) (4) (5)4.5.1. event.registerForeignFetch(options) (2)4.6. FetchEvent (2)4.7. ForeignFetchEvent (2)4.8. ExtendableMessageEvent (2)5.2. Understanding Cache Lifetimes (2)6.1. Secure Context (2) (3) (4) (5)6.2. Content Security Policy6.3.1. Origin restriction (2) (3)6.4. Cross-Origin Resources and CORS6.5. Implementer Concerns (2) (3)6.6. Privacy (2)7. Storage Considerations (2)8. Extensibility8.4. Request Functional Event DispatchUpdateInstall (2)Run Service WorkerTerminate Service WorkerHandle FetchHandle Foreign FetchUpdate State (2)Match Service Worker for Foreign FetchGet Newest WorkerService Worker Script Request (2)Service Worker Script ResponseSyntax is a type of web worker. A service worker executes in the registering service worker client’s origin.

+

A service worker has an associated state#dfn-stateReferenced in:2.2. Service Worker Registration (2) (3)3.1. ServiceWorker3.1.2. state3.2.5. update()4.1.3. skipWaiting()4.4.1. event.waitUntil(f) (2) (3)Handle Fetch (2)Handle Foreign Fetch (2)Handle Functional Event (2)Update State (2), which is one of parsed, installing, installed, activating, activated, and redundant. It is initially parsed.

+

A service worker has an associated script url#dfn-script-urlReferenced in:3.1.1. scriptURL3.2.5. update()RegisterUpdate (2) (3)Soft UpdateRun Service Worker (2) (3) (a URL).

+

A service worker has an associated type#dfn-typeReferenced in:3.2.5. update()UpdateSoft UpdateRun Service Worker which is either "classic" or "module". Unless stated otherwise, it is "classic".

+

A service worker has an associated containing service worker registration#dfn-containing-service-worker-registrationReferenced in:2.1. Service Worker2.4. Selection and Use3.2.6. unregister()4.1.2. registration4.1.3. skipWaiting() (2) (3)4.3.4. claim()4.5.1. event.registerForeignFetch(options)4.9. Events (2)InstallRun Service WorkerTerminate Service WorkerHandle Fetch (2) (a service worker registration), which contains itself.

+

A service worker has an associated id#dfn-service-worker-idReferenced in:Update (an opaque string), which uniquely identifies itself during the lifetime of its containing service worker registration.

+

A service worker is dispatched a set of lifecycle events#dfn-lifecycle-eventsReferenced in:4.4. ExtendableEvent4.9. Events (2), install and activate, and functional events#dfn-functional-eventsReferenced in:2.5. Task Sources3.1.2. state (2)4.4.1. event.waitUntil(f)4.6. FetchEvent4.7. ForeignFetchEvent4.9. Events (2)8.2. Define Functional Event8.3. Define Event Handler8.4. Request Functional Event Dispatch (2) (3) including fetch.

+

A service worker has an associated script resource#dfn-script-resourceReferenced in:2.1. Service Worker (2)6.2. Content Security Policy (2)Update (2)Run Service Worker (2)Service Worker Script Request (2)Service Worker Script ResponseSyntax (a script), which represents its own script resource. It is initially set to null. A script resource has an associated has ever been evaluated flag#dfn-has-ever-been-evaluated-flagReferenced in:Run Service Worker (2). It is initially unset. A script resource has an associated HTTPS state#dfn-https-stateReferenced in:Run Service Worker which is "none", "deprecated", or "modern". Unless stated otherwise, it is "none".

+

A service worker has an associated script resource map#dfn-script-resource-mapReferenced in:6.3.2. importScripts(urls) (2) (3)6.6. Privacy which is a List of the Record {[[key]], [[value]]} where [[key]] is a URL and [[value]] is a script resource.

+

A service worker has an associated skip waiting flag#dfn-skip-waiting-flagReferenced in:3.6. Events4.1.3. skipWaiting()Install (2) (3). Unless stated otherwise it is unset.

+

A service worker has an associated imported scripts updated flag#dfn-imported-scripts-updated-flagReferenced in:6.3.2. importScripts(urls) (2)Install. It is initially unset.

+

A service worker has an associated set of event types to handle#dfn-set-of-event-types-to-handleReferenced in:Run Service WorkerHandle FetchHandle Functional Event whose element type is an event listener’s event type. It is initially set to null.

+

A service worker has an associated list of foreign fetch scopes#dfn-foreign-fetch-scopesReferenced in:4.5.1. event.registerForeignFetch(options)Match Service Worker for Foreign Fetch whose element type is a URL. It is initially empty.

+

A service worker has an associated list of foreign fetch origins#dfn-foreign-fetch-originsReferenced in:4.5.1. event.registerForeignFetch(options)Handle Foreign Fetch (2) whose element type is a URL. It is initially empty.

+
+

2.1.1. Lifetime

+

The lifetime of a service worker is tied to the execution lifetime of events and not references held by service worker clients to the ServiceWorker object.

+

A user agent may terminate service workers at any time it:

+
    +
  • Has no event to handle. +
  • Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events. +
+
+
+
+

2.2. Service Worker Registration

+

A service worker registration#dfn-service-worker-registrationReferenced in:2.1. Service Worker2.2. Service Worker Registration (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)2.2.1. Lifetime (2) (3) (4)2.4. Selection and Use (2) (3) (4) (5) (6) (7) (8)2.6. User Agent Shutdown (2) (3)3.2. ServiceWorkerRegistration (2) (3)3.2.6. unregister() (2)3.4. ServiceWorkerContainer (2)3.4.2. ready3.4.3. register(scriptURL, options) (2)3.6. Events (2)6.1. Secure Context (2)6.6. Privacy8.1. Define API bound to Service Worker Registration8.4. Request Functional Event DispatchAppendix A: Algorithms (2) (3)Soft UpdateInstallActivateHandle Functional EventHandle Service Worker Client UnloadSet Registration (2)Clear RegistrationMatch Service Worker RegistrationGet RegistrationGet Newest Worker is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. A user agent may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

+

A service worker registration has an associated scope url#dfn-scope-urlReferenced in:2.2. Service Worker Registration (2) (3)2.2.1. Lifetime2.4. Selection and Use3.2.4. scope3.2.5. update()3.2.6. unregister()3.4.3. register(scriptURL, options) (2)4.5.1. event.registerForeignFetch(options)Appendix A: Algorithms (2)UpdateSoft UpdateInstallActivateSet RegistrationClear RegistrationService Worker Script Response (a URL).

+

A service worker registration has an associated registering script url (a URL).

+

A service worker registration has an associated installing worker#dfn-installing-workerReferenced in:2.2. Service Worker Registration2.6. User Agent Shutdown (2)3.1.2. state (2)3.2.1. installing3.6. Events4.4.1. event.waitUntil(f)4.9. EventsInstall (2) (3) (4) (5) (6) (7) (8) (9) (10)Handle User Agent Shutdown (2)Clear Registration (2) (3) (4) (5)Get Newest Worker (2) (a service worker) whose state is installing. It is initially set to null.

+

A service worker registration has an associated waiting worker#dfn-waiting-workerReferenced in:2.2. Service Worker Registration2.6. User Agent Shutdown3.1.2. state3.2.2. waiting4.1.3. skipWaiting()4.4.1. event.waitUntil(f) (2)Install (2) (3) (4) (5) (6) (7) (8) (9)Activate (2)Handle Service Worker Client UnloadHandle User Agent ShutdownClear Registration (2) (3) (4) (5)Get Newest Worker (2) (a service worker) whose state is installed. It is initially set to null.

+

A service worker registration has an associated active worker#dfn-active-workerReferenced in:2.2. Service Worker Registration (2) (3) (4) (5) (6)2.3. Service Worker Client2.4. Selection and Use (2) (3)2.6. User Agent Shutdown3.1.2. state (2) (3)3.2.3. active3.4.2. ready (2) (3)3.6. Events4.1.3. skipWaiting()4.3.4. claim() (2) (3)4.4.1. event.waitUntil(f)4.9. EventsRegisterActivate (2) (3) (4) (5) (6) (7)Run Service WorkerHandle Fetch (2) (3)Handle Functional Event (2)Clear Registration (2) (3) (4) (5)Match Service Worker for Foreign FetchGet Newest Worker (2) (a service worker) whose state is either activating or activated. It is initially set to null.

+

A service worker registration has an associated last update check time#dfn-last-update-check-timeReferenced in:Update (2) (3)Handle Fetch (2) (3)Handle Functional Event. It is initially set to null.

+

A service worker registration has an associated uninstalling flag#dfn-uninstalling-flagReferenced in:RegisterUpdateHandle Service Worker Client UnloadUnregister (2)Match Service Worker Registration. It is initially unset.

+

A service worker registration has one or more task queues#dfn-service-worker-registration-task-queueReferenced in:2.2. Service Worker Registration (2)Run Service WorkerTerminate Service Worker that back up the tasks from its active worker’s event loop’s corresponding task queues. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker’s tasks to the service worker registration’s task queues when the active worker is terminated and re-queues those tasks to the active worker’s event loop’s corresponding task queues when the active worker spins off. Unlike the task queues owned by event loops, the service worker registration’s task queues are not processed by any event loops in and of itself.

+
+

2.2.1. Lifetime

+

A user agent must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of service worker registration’s scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

+
+
+
+

2.3. Service Worker Client

+

A service worker client#dfn-service-worker-clientReferenced in:2.1. Service Worker2.1.1. Lifetime2.2.1. Lifetime2.3. Service Worker Client (2) (3) (4) (5) (6)2.4. Selection and Use (2) (3) (4) (5) (6) (7) (8) (9)3.2.6. unregister() (2)3.4. ServiceWorkerContainer3.6. Events (2)4.1. ServiceWorkerGlobalScope4.2. Client4.3.1. get(id)4.3.2. matchAll(options) (2)4.3.4. claim()4.8.2. event.origin6.1. Secure Context (2)6.3.1. Origin restrictionAppendix A: AlgorithmsCreate JobInstall (2)Activate (2)Run Service WorkerHandle Fetch (2)Handle Service Worker Client Unload (2) (3)UnregisterNotify Controller ChangeCreate ClientCreate Window Client is an environment settings object that specifies various settings for its JavaScript global environment.

+

A service worker client has an associated active worker#dfn-service-worker-client-active-workerReferenced in:3.2.6. unregister()3.4.1. controller3.6. Events4.2.8. navigate(url)4.3.2. matchAll(options)Handle Fetch (2) (3) (4) (an active worker) which currently controls it. It is initially set to null.

+

A service worker client has an associated id#dfn-service-worker-client-idReferenced in:4.2.3. id4.3.1. get(id)Handle Fetch (an opaque string), which uniquely identifies itself during its lifetime. It is initially set to a new unique value when the corresponding environment settings object that it represents is created.

+

A service worker client has an associated frame type#dfn-service-worker-client-frame-typeReferenced in:4.2.2. frameType, which is one of auxiliary, top-level, nested, and none. Unless stated otherwise it is none.

+

A window client#dfn-window-clientReferenced in:4.2.2. frameType (2) (3)4.3.1. get(id)4.3.2. matchAll(options) (2) (3)ActivateHandle Fetch is a service worker client whose global object is a Window object.

+

A dedicated worker client#dfn-dedicatedworker-clientReferenced in:2.3. Service Worker Client4.3.2. matchAll(options) is a service worker client whose global object is a DedicatedWorkerGlobalScope object.

+

A shared worker client#dfn-sharedworker-clientReferenced in:2.3. Service Worker Client4.3.2. matchAll(options)Activate is a service worker client whose global object is a SharedWorkerGlobalScope object.

+

A worker client#dfn-worker-clientReferenced in:2.4. Selection and UseRun Job is either a dedicated worker client or a shared worker client.

+
+
+

2.4. Selection and Use

+

A service worker client independently selects and uses a service worker registration for its own loading and its subresources. The selection#dfn-service-worker-registration-selectionReferenced in:2.4. Selection and Use (2) (3) of a service worker registration, upon a non-subresource request, is a process of either matching a service worker registration from scope to registration map or inheriting an existing service worker registration from its parent or owner context depending on the request’s url.

+

When the request’s url is not local, a service worker client matches a service worker registration from scope to registration map. That is, the service worker client attempts to consult a service worker registration whose scope url matches its creation url.

+

When the request’s url is local, if the service worker client’s responsible browsing context is a nested browsing context or the service worker client is a worker client, the service worker client inherits the service worker registration from its parent browsing context’s environment or one of the worker’s Documents' environment, respectively, if it exists.

+

If the selection was successful, the selected service worker registration’s active worker starts to control#dfn-controlReferenced in:2.3. Service Worker Client2.4. Selection and Use3.2.6. unregister()3.6. EventsService Worker Script Response the service worker client. Otherwise, the flow returns to fetch where it falls back to the default behavior. When a service worker client is controlled by an active worker, it is considered that the service worker client is using#dfn-useReferenced in:2.4. Selection and Use3.6. Events4.1.3. skipWaiting()InstallActivateHandle FetchHandle Service Worker Client Unload (2)Unregister the active worker’s containing service worker registration.

+
+
+

2.5. Task Sources

+

The following additional task sources are used by service workers.

+
+
The handle fetch task source#dfn-handle-fetch-task-sourceReferenced in:2.2. Service Worker RegistrationTerminate Service Worker (2)Handle FetchHandle Foreign Fetch +
This task source is used for dispatching fetch events to service workers. +
The handle functional event task source#dfn-handle-functional-event-task-sourceReferenced in:2.2. Service Worker RegistrationTerminate Service Worker (2)Handle Functional Event +
+ This task source is used for features that dispatch other functional events, e.g. push events, to service workers. +

A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. For instance, a user agent may use a different task source for task events from other task sources.

+
+
+
+

2.6. User Agent Shutdown

+

A user agent must maintain the state of its stored service worker registrations across restarts with the following rules:

+ +

+

To attain this, the user agent must invoke Handle User Agent Shutdown when it terminates.

+
+
+
+

3. Client Context

+
+ Bootstrapping with a ServiceWorker: +
// scope defaults to the path the script sits in
+// "/" in this example
+navigator.serviceWorker.register("/serviceworker.js").then(
+  function(registration) {
+    console.log("success!");
+    if (registration.installing) {
+      registration.installing.postMessage("Howdy from your installing page.");
+    }
+  },
+  function(why) {
+    console.error("Installing the worker failed!:", why);
+  });
+
+
+

3.1. ServiceWorker

+
[Exposed=(Window,Worker)]
+interface ServiceWorker : EventTarget {
+  readonly attribute USVString scriptURL;
+  readonly attribute ServiceWorkerState state;
+  void postMessage(any message, optional sequence<Transferable> transfer);
 
   // event
-  attribute EventHandler onstatechange;
-
-  // terminate() method inherited from Worker should not be accessible.
+  attribute EventHandler onstatechange;
 };
-
-enum ServiceWorkerState {
-  "installing",
-  "installed",
-  "activating",
-  "activated",
-  "redundant"
-};
-
-    

A ServiceWorker object represents a service worker. Each ServiceWorker object is associated with a service worker. Multiple separate objects implementing the ServiceWorker interface across document environments and worker environments can all be associated with the same service worker simultaneously.

- -

A ServiceWorker object has an associated ServiceWorkerState object which is itself associated with service worker's state.

- -

The terminate() method inherited from Worker, when called on the context object, should throw an "InvalidAccessError" exception.

- -

The postMessage(message, transfer) method inherited from Worker, when called on the context object, should throw an "InvalidStateError" exception if the state attribute value of the context object is "redundant". Otherwise, it should run a worker, if not running, for a script with its associated service worker serviceWorker's script url and serviceWorker's environment settings object, and run as defined on the Worker interface.

- -

Communication with these workers is provided via standard HTML5 messaging APIs, and messaging occurs as per usual with Web Workers.

- - -

scriptURL

- -

The scriptURL attribute must return service worker's serialized script url.

- -

For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

- -// Script on the page https://example.com/app.html -navigator.serviceWorker.register("/service_worker.js", { scope: "/" }); - -

The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

-
- - -

state

- -

The state attribute must return the value (in ServiceWorkerState enumeration) corresponding to the first matching statement, switching on service worker's state:

- +ServiceWorker implements AbstractWorker; + +enum ServiceWorkerState { + "installing", + "installed", + "activating", + "activated", + "redundant" +}; +
+

A ServiceWorker#service-worker-interfaceReferenced in:2.1.1. Lifetime3.1. ServiceWorker (2) (3) (4) (5) (6)3.1.3. postMessage(message, transfer)3.1.4. Event handler3.2. ServiceWorkerRegistration (2) (3)3.2.1. installing (2)3.2.2. waiting (2)3.2.3. active (2)3.4. ServiceWorkerContainer3.4.1. controller (2)3.5. ServiceWorkerMessageEvent (2) (3)3.5.4. event.source3.6. Events (2)4.1. ServiceWorkerGlobalScope4.2.4. postMessage(message, transfer)4.8. ExtendableMessageEvent (2)Update State object represents a service worker. Each ServiceWorker object is associated with a service worker. Multiple separate objects implementing the ServiceWorker interface across document environments and worker environments can all be associated with the same service worker simultaneously.

+

A ServiceWorker object has an associated ServiceWorkerState object which is itself associated with service worker’s state.

+
+

3.1.1. scriptURL

+

The scriptURL#service-worker-url-attributeReferenced in:3.1. ServiceWorker3.1.1. scriptURL attribute must return the service worker’s serialized script url.

+
+ +

For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

+
// Script on the page https://example.com/app.html
+navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
+

The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

+
+
+
+

3.1.2. state

+

The state#service-worker-state-attributeReferenced in:3.1. ServiceWorker3.1.2. state3.1.3. postMessage(message, transfer)3.6. Events attribute must return the value (in ServiceWorkerState#service-worker-state-enumReferenced in:3.1. ServiceWorker (2) (3) enumeration) corresponding to the first matching statement, switching on the service worker’s state:

-
installing
-
"installing" -

The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

- -
installed
-
"installed" -

The service worker in this state is considered a waiting worker.

- -
activating
-
"activating" -

The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

- -
activated
-
"activated" -

The service worker in this state is considered an active worker ready to handle functional events.

- -
redundant
-
"redundant" -

A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

+
installing +
+ "installing" +

The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

+
installed +
+ "installed" +

The service worker in this state is considered a waiting worker.

+
activating +
+ "activating" +

The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

+
activated +
+ "activated" +

The service worker in this state is considered an active worker ready to handle functional events.

+
redundant +
+ "redundant" +

A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

- - - -

Event handler

- -

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorker interface:

- - - - - - - - - - - - - - + +
+

3.1.3. postMessage(message, transfer)

+

The postMessage(message, transfer)#service-worker-postmessage-methodReferenced in:3.1. ServiceWorker3.1.3. postMessage(message, transfer) method must run these steps or their equivalent:

+
    +
  1. If the state attribute value of the context object is "redundant", throw an "InvalidStateError" exception and abort these steps. +
  2. Let newPorts be an empty array. +
  3. Let transferMap be an empty association list of Transferable objects to placeholder objects. +
  4. + If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps. +
    2. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts. +
    +
  5. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps. +
  6. Let serviceWorker be the service worker represented by the context object. +
  7. Invoke Run Service Worker algorithm with serviceWorker as the argument. +
  8. Let destination be the ServiceWorkerGlobalScope object associated with serviceWorker. +
  9. + If the method was invoked with a second argument transfer, run these substeps: +
      +
    1. Let newOwner be the destination’s environment settings object. +
    2. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts). +
    +
  10. Make newPorts into a read only array. +
  11. + Queue a task that runs the following steps: +
      +
    1. Create an event e that uses the ExtendableMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action. +
    2. Let the data attribute of e be initialized to clonedMessage. +
    3. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object. +
    4. If the global object globalObject specified by the incumbent settings object is a ServiceWorkerGlobalScope object, let the source attribute of e be initialized to a new ServiceWorker object that represents globalObject’s service worker. +
    5. Else if globalObject is a Window object, let the source attribute of e be initialized to a new WindowClient object that represents globalObject’s browsing context. +
    6. Else, let it be initialized to a new Client object that represents globalObject’s worker environment. +
    7. Let the ports attribute of e be initialized to newPorts. +
    8. Dispatch e at destination. +
    +

    The task must use the DOM manipulation task source.

    +
+
+
+

3.1.4. Event handler

+

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorker interface:

+
event handlerevent handler event type
onstatechangestatechange
+ + + + +
event handler + event handler event type +
onstatechange#service-worker-onstatechange-attributeReferenced in:3.1. ServiceWorker + statechange
-
- - - -

ServiceWorkerRegistration

+
+
+
+

3.2. ServiceWorkerRegistration

+
[Exposed=(Window,Worker)]
+interface ServiceWorkerRegistration : EventTarget {
+  [Unforgeable] readonly attribute ServiceWorker? installing;
+  [Unforgeable] readonly attribute ServiceWorker? waiting;
+  [Unforgeable] readonly attribute ServiceWorker? active;
 
-[Exposed=(Window,Worker)]
-interface ServiceWorkerRegistration : EventTarget {
-  [Unforgeable] readonly attribute ServiceWorker? installing;
-  [Unforgeable] readonly attribute ServiceWorker? waiting;
-  [Unforgeable] readonly attribute ServiceWorker? active;
+  readonly attribute USVString scope;
 
-  readonly attribute USVString scope;
-
-  void update();
-  Promise<boolean> unregister();
+  [NewObject] Promise<void> update();
+  [NewObject] Promise<boolean> unregister();
 
   // event
-  attribute EventHandler onupdatefound;
-};
-
-    

A ServiceWorkerRegistration object represents a service worker registration. Each ServiceWorkerRegistration object is associated with a service worker registration (a service worker registration). Multiple separate objects implementing the ServiceWorkerRegistration interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

- -

A ServiceWorkerRegistration has an associated service worker client (a service worker client).

- - -

installing

- -

installing attribute must return a ServiceWorker object that represents the installing worker.

-
- - -

waiting

- -

waiting attribute must return a ServiceWorker object that represents the waiting worker.

-
- - -

active

- -

active attribute must return a ServiceWorker object that represents the active worker.

-
- - -

scope

- -

The scope attribute must return service worker registration's serialized scope url.

- -

In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

-
- - -

update()

- -

update() pings the server for an updated version of this script without consulting caches. This is conceptually the same operation that UA does maximum once per every 24 hours.

-

update() method must run these steps or their equivalent:

- + attribute EventHandler onupdatefound; +}; +
+

A ServiceWorkerRegistration#service-worker-registration-interfaceReferenced in:2.2.1. Lifetime3.2. ServiceWorkerRegistration (2) (3) (4)3.2.7. Event handler3.4. ServiceWorkerContainer (2) (3)3.4.2. ready3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()3.6. Events4.1. ServiceWorkerGlobalScope4.1.2. registration8.1. Define API bound to Service Worker RegistrationRegisterUpdateInstall (2) object represents a service worker registration. Each ServiceWorkerRegistration object is associated with a service worker registration#dfn-service-worker-registration-interface-service-worker-registrationReferenced in:3.2.1. installing3.2.2. waiting3.2.3. active3.2.4. scope3.2.5. update()3.2.6. unregister()3.6. Events (a service worker registration). Multiple separate objects implementing the ServiceWorkerRegistration interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

+
+ +

installing#service-worker-registration-installing-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.1. installing attribute must return the result of running these steps or their equivalent:

    -
  1. Invoke Soft Update algorithm, or its equivalent, passing the service worker registration registration as the argument.
  2. +
  3. Let installingWorker be the ServiceWorker object that represents the service worker registration’s installing worker. +
  4. Return installingWorker.
- - - - -

unregister()

- -

The unregister() method unregisters the service worker registration. It is important to note that the currently controlled service worker client's active worker's containing service worker registration is effective until all the service worker clients (including itself) using this service worker registration unload. That is, unregister() method only affects subsequent navigations.

- -

unregister() method must return the result of running these steps or their equivalent:

- - +

The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

+
+
+ +

waiting#service-worker-registration-waiting-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.2. waiting attribute must return the result of running these steps or their equivalent:

    -
  1. Let scopeURL be the scope url of the service worker registration.
  2. -
  3. Return the result of running the Unregister algorithm, or their equivalent, passing the service worker client client, and scopeURL as the arguments.
  4. +
  5. Let waitingWorker be the ServiceWorker object that represents the service worker registration’s waiting worker. +
  6. Return waitingWorker.
- - - - -

Event handler

- -

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

- - - - - - - - - - - - - - +

The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

+ +
+ +

active#service-worker-registration-active-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.3. active attribute must return the result of running these steps or their equivalent:

+
    +
  1. Let activeWorker be the ServiceWorker object that represents the service worker registration’s active worker. +
  2. Return activeWorker. +
+

The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

+
+
+

3.2.4. scope

+

The scope#service-worker-registration-scope-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.4. scope attribute must return service worker registration’s serialized scope url.

+

In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

+
+
+

3.2.5. update()

+

update()#service-worker-registration-update-methodReferenced in:3.2. ServiceWorkerRegistration3.2.5. update() method must run these steps or their equivalent:

+
    +
  1. Let p be a promise. +
  2. Let registration be the service worker registration. +
  3. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
  4. If newestWorker is null, reject p with an "InvalidStateError" exception and abort these steps. +
  5. If the context object’s relevant settings object’s global object globalObject is a ServiceWorkerGlobalScope object, and globalObject’s associated service worker’s state is installing, reject p with an "InvalidStateError" exception and abort these steps. +
  6. Let job be the result of running Create Job with update, registration’s scope url, newestWorker’s script url, p, and the context object’s relevant settings object client. +
  7. Set job’s worker type to newestWorker’s type. +
  8. + Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job. +
    +
  9. Return p. +
+
+
+ +

The unregister() method unregisters the service worker registration. It is important to note that the currently controlled service worker client’s active worker’s containing service worker registration is effective until all the service worker clients (including itself) using this service worker registration unload. That is, the unregister() method only affects subsequent navigations.

+

unregister()#service-worker-registration-unregister-methodReferenced in:3.2. ServiceWorkerRegistration3.2.6. unregister() (2) (3) method must return the result of running these steps or their equivalent:

+
    +
  1. Let p be a promise. +
  2. Let job be the result of running Create Job with unregister, the scope url of the service worker registration, null, p, and the context object’s relevant settings object client. +
  3. + Run the following substep in parallel: +
      +
    1. Invoke Schedule Job with job. +
    +
  4. Return p. +
+
+
+

3.2.7. Event handler

+

The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

+
event handlerevent handler event type
onupdatefoundupdatefound
+ + + + +
event handler + event handler event type +
onupdatefound#service-worker-registration-onupdatefound-attributeReferenced in:3.2. ServiceWorkerRegistration + updatefound
-
- - - -

navigator.serviceWorker

- -partial interface Navigator { - readonly attribute ServiceWorkerContainer serviceWorker; +
+
+
+ +
partial interface Navigator {
+  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
 };
 
-partial interface WorkerNavigator {
-  readonly attribute ServiceWorkerContainer serviceWorker;
-};
-
-    

The serviceWorker attribute must return the ServiceWorkerContainer object for the context object.

- - - -

ServiceWorkerContainer

- -[Exposed=(Window,Worker)] -interface ServiceWorkerContainer : EventTarget { - [Unforgeable] readonly attribute ServiceWorker? controller; - readonly attribute Promise<ServiceWorkerRegistration> ready; +partial interface WorkerNavigator { + [SameObject] readonly attribute ServiceWorkerContainer serviceWorker; +}; +
+

The serviceWorker#navigator-service-worker-attributeReferenced in:3.3. navigator.serviceWorker (2) (3) attribute must return the ServiceWorkerContainer object that is associated with the context object.

+
+
+

3.4. ServiceWorkerContainer

+
[Exposed=(Window,Worker)]
+interface ServiceWorkerContainer : EventTarget {
+  [Unforgeable] readonly attribute ServiceWorker? controller;
+  [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
 
-  Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
+  [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
 
-  Promise<ServiceWorkerRegistration> getRegistration(optional USVString clientURL = "");
-  Promise<sequence<ServiceWorkerRegistration>?> getRegistrations();
+  [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
+  [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
 
 
   // events
-  attribute EventHandler oncontrollerchange;
-  attribute EventHandler onerror;
+  attribute EventHandler oncontrollerchange;
+  attribute EventHandler onerror;
+  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
 };
-
-dictionary RegistrationOptions {
-  USVString scope;
+
+
dictionary RegistrationOptions#dictdef-serviceworkercontainer-registrationoptionsReferenced in:3.4. ServiceWorkerContainer {
+  USVString scope#dom-registrationoptions-scopeReferenced in:3.4.3. register(scriptURL, options) (2);
+  WorkerType type#dom-registrationoptions-typeReferenced in:3.4.3. register(scriptURL, options) = "classic";
 };
-
-
-  

A ServiceWorkerContainer provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

-

A ServiceWorkerContainer has an associated service worker client, which is a service worker client whose global object is associated with the Navigator object or the WorkerNavigator object that the ServiceWorkerContainer is retrieved from.

- -

A ServiceWorkerContainer object has an associated ready promise (a promise). It is initially set to null.

- - -

controller

- -

controller attribute must return a ServiceWorker object that represents the context object's service worker client's active worker.

-

navigator.serviceWorker.controller returns null if the request is a force refresh (shift+refresh).

-
- -

ready

- -

ready attribute must return the result of running these steps or their equivalent:

- -
    -
  1. If the context object's ready promise is null, then: +
+

The user agent must create a ServiceWorkerContainer object when a Navigator object or a WorkerNavigator object is created and associate it with that object.

+

A ServiceWorkerContainer#service-worker-container-interfaceReferenced in:3.3. navigator.serviceWorker (2) (3)3.4. ServiceWorkerContainer (2) (3) (4) (5) (6)3.4.6. Event handlers3.6. Events4.2.4. postMessage(message, transfer) (2) (3)Notify Controller Change provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

+

A ServiceWorkerContainer has an associated service worker client#dfn-service-worker-container-interface-clientReferenced in:3.4.1. controller3.4.2. ready3.4.3. register(scriptURL, options)3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()3.6. Events4.2.4. postMessage(message, transfer) (2) (3) (4)Notify Controller Change, which is a service worker client whose global object is associated with the Navigator object or the WorkerNavigator object that the ServiceWorkerContainer is retrieved from.

+

A ServiceWorkerContainer object has an associated ready promise#dfn-ready-promiseReferenced in:3.4.2. ready (2) (3) (4) (5) (a promise). It is initially set to a new promise.

+
+ +

controller#service-worker-container-controller-attributeReferenced in:3.4. ServiceWorkerContainer3.4.1. controller (2)3.6. Events attribute must return the result of running these steps or their equivalent:

+
    +
  1. Let client be the context object’s service worker client. +
  2. If client is not a secure context, return undefined. +
  3. Return the ServiceWorker object that represents client’s active worker. +
+

navigator.serviceWorker.controller returns null if the request is a force refresh (shift+refresh). The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

+

The behavior of the attribute getter in non-secure contexts is in discussion.

+
+
+ +

ready#service-worker-container-ready-attributeReferenced in:3.4. ServiceWorkerContainer3.4.2. ready (2) attribute must return the result of running these steps or their equivalent:

+
    +
  1. If the context object’s ready promise is settled, return the context object’s ready promise. +
  2. Let client be the context object’s service worker client. +
  3. If client is not a secure context, return the context object’s ready promise rejected with a "SecurityError" exception. +
  4. Let registration be null. +
  5. Let clientURL be client’s creation url. +
  6. + Run the following substeps in parallel:
      -
    1. Set the context object's ready promise to a new promise.
    2. +
    3. + CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
        +
      1. Set registration to the result value. +
      +
    4. + Else: +
        +
      1. Wait until scope to registration map has a new entry. +
      2. Jump to the step labeled CheckRegistration. +
      +
    5. + If registration’s active worker is null, wait until registration’s active worker changes. +

      Implementers should consider this condition is met when the corresponding registration request gets to the step 7 of Activate algorithm.

      +
    6. Resolve context object’s ready promise with the ServiceWorkerRegistration object which represents registration.
    -
  7. -
  8. If the context object's ready promise is settled, then: +
  9. Return context object’s ready promise. +
+

When the ready attribute is accessed in a secure context, the returned promise will never reject. Instead, it waits until the promise resolves with a service worker registration that has an active worker.

+
+
+ +

The register(scriptURL, options) method creates or updates a service worker registration for the given scope url. If successful, a service worker registration ties the provided scriptURL to a scope url, which is subsequently used for navigation matching.

+

register(scriptURL, options)#service-worker-container-register-methodReferenced in:3.4. ServiceWorkerContainer3.4.3. register(scriptURL, options) (2) method must run these steps or their equivalent:

+
    +
  1. Let p be a promise. +
  2. Let client be the context object’s service worker client. +
  3. If client is not a secure context, reject p with a "SecurityError" exception and abort these steps. +
  4. Let scriptURL be the result of parsing scriptURL with entry settings object’s API base URL. +
  5. If scriptURL is failure, reject p with a TypeError and abort these steps. +
  6. If scriptURL’s scheme is not one of "http" and "https", reject p with a TypeError and abort these steps. +
  7. If any of the strings in scriptURL’s path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps. +
  8. Let scopeURL be null. +
  9. + If options.scope is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

    The scope url for the registration is set to the location of the service worker script by default.

    +
  10. Else, set scopeURL to the result of parsing options.scope with entry settings object’s API base URL. +
  11. If scopeURL is failure, reject p with a TypeError and abort these steps. +
  12. If scopeURL’s scheme is not one of "http" and "https", reject p with a TypeError and abort these steps. +
  13. If any of the strings in scopeURL’s path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps. +
  14. Let job be the result of running Create Job with register, scopeURL, scriptURL, p, and client. +
  15. Set job’s worker type to options.type. +
  16. + Run the following substep in parallel:
      -
    1. Return the context object's ready promise.
    2. +
    3. Invoke Schedule Job with job.
    -
  17. -
  18. Let registration be null.
  19. -
  20. Let clientURL be the context object's service worker client's creation url.
  21. -
  22. Run the following substeps in parallel: +
  23. Return p. +
+
+
+ +

getRegistration(clientURL)#service-worker-container-getregistration-methodReferenced in:3.4. ServiceWorkerContainer3.4.4. getRegistration(clientURL) method must run these steps or their equivalent:

+
    +
  1. Let client be the context object’s service worker client. +
  2. If client is not a secure context, return a promise rejected with a "SecurityError" exception. +
  3. Let clientURL be the result of parsing clientURL with entry settings object’s API base URL. +
  4. If clientURL is failure, return a promise rejected with a TypeError. +
  5. If the origin of clientURL is not client’s origin, return a promise rejected with a "SecurityError" exception. +
  6. Let promise be a new promise. +
  7. + Run the following substeps in parallel:
      -
    1. CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: -
        -
      1. Set registration to the result value.
      2. -
      -
    2. -
    3. Else: -
        -
      1. Wait until scope to registration map has a new entry.
      2. -
      3. Jump to the step labeled CheckRegistration.
      4. -
      -
    4. -
    5. If registration's active worker is null, then: -
        -
      1. Wait until registration's active worker changes.
      2. -
      -

      Implementers should consider this condition is met when the corresponding registration request gets to the step 1.8 of Activate algorithm.

      -
    6. -
    7. Resolve context object's ready promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
    8. -
    -
  8. -
  9. Return context object's ready promise.
  10. -
- -

The ready attribute is designed in a way that the returned promise will never reject. Instead, it waits until the promise resolves with a service worker registration that has an active worker.

- - - -

register(scriptURL, options)

- -

The register(scriptURL, options) method creates or updates a service worker registration for the given scope url. If successful, a service worker registration ties the provided script url to a scope url, which is subsequently used for navigation matching.

- -

register(scriptURL, options) method must return the result of running these steps or their equivalent:

- -
    -
  1. Let scriptURL be the result of parsing scriptURL with entry settings object's API base URL.
  2. -
  3. If scriptURL is failure, return a promise rejected with a TypeError.
  4. -
  5. Let scopeURL be null.
  6. -
  7. If the optional argument options is omitted or options.scope is not present, set scopeURL to the result of parsing a string "./" with scriptURL.
  8. -

    The scope url for the registration is set to the location of the service worker script by default.

    -
  9. Else, set scopeURL to the result of parsing options.scope with entry settings object's API base URL.
  10. -
  11. If scopeURL is failure, return a promise rejected with a TypeError.
  12. -
  13. Return the result of running the Register algorithm, or their equivalent, passing the service worker client client, scriptURL, scopeURL as the arguments.
  14. -
-
-
- - -

getRegistration(clientURL)

- -

getRegistration(clientURL) method must run these steps or their equivalent:

- - -
    -
  1. Let clientURL be the result of parsing clientURL with entry settings object's API base URL.
  2. -
  3. If clientURL is failure, return a promise rejected with a TypeError.
  4. -
  5. If the origin of clientURL is not the context object's service worker client's origin, return a promise with a "SecurityError" exception.
  6. -
  7. Let promise be a new promise.
  8. -
  9. Run the following substeps in parallel: -
      -
    1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument.
    2. -
    3. If registration is not null, then: -
        -
      1. Resolve promise with a ServiceWorkerRegistration object, setting its service worker client to service worker client, which represents registration.
      2. -
      -
    4. -
    5. Else: -
        -
      1. Resolve promise with undefined.
      2. -
      -
    6. +
    7. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument. +
    8. + If registration is not null, then: +
        +
      1. Resolve promise with the ServiceWorkerRegistration object which represents registration. +
      +
    9. + Else: +
        +
      1. Resolve promise with undefined. +
    -
  10. -
  11. Return promise.
  12. -
-
-
- - -

getRegistrations()

- -

getRegistrations() method must run these steps or their equivalent:

- - - - - -
    -
  1. Let promise be a new promise.
  2. -
  3. Run the following substeps in parallel: +
  4. Return promise. +
+
+
+ +

getRegistrations()#service-worker-container-getregistrations-methodReferenced in:3.4. ServiceWorkerContainer3.4.5. getRegistrations() method must run these steps or their equivalent:

+
    +
  1. Let client be the context object’s service worker client. +
  2. If client is not a secure context, return a promise rejected with a "SecurityError" exception. +
  3. Let promise be a new promise. +
  4. + Run the following substeps in parallel:
      -
    1. Let array be an empty array.
    2. -
    3. For each Record {[[key]], [[value]]} entry of its scope to registration map: -
        -
      1. If the origin of the result of parsing entry.[[key]] is its service worker client's origin, then: -
          -
        1. Add a ServiceWorkerRegistration object, setting its service worker client to service worker client, associated with entry.[[value]] to the array.
        2. -
        -
      2. -
      -
    4. -
    5. Resolve promise with array.
    6. -
    -
  5. -
  6. Return promise.
  7. -
- - - - -

Event handlers

- -

The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

- - - - - - - - - - - - - - - - - - +
  • Let array be an empty array. +
  • + For each Record {[[key]], [[value]]} entry of scope to registration map: +
      +
    1. If the origin of the result of parsing entry.[[key]] is the same as client’s origin, add the ServiceWorkerRegistration object associated with entry.[[value]] to the array. +
    +
  • Resolve promise with array. + +
  • Return promise. + + +
    +

    3.4.6. Event handlers

    +

    The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

    +
  • event handlerevent handler event type
    oncontrollerchangecontrollerchange
    onerrorerror
    + + + + + + +
    event handler + event handler event type +
    oncontrollerchange#service-worker-container-oncontrollerchange-attributeReferenced in:3.4. ServiceWorkerContainer + controllerchange +
    onerror#service-worker-container-onerror-attributeReferenced in:3.4. ServiceWorkerContainer + error +
    onmessage#service-worker-container-onmessage-attributeReferenced in:3.4. ServiceWorkerContainer + message
    -
    - - - -

    Events

    - -

    The following events are dispatched on ServiceWorker object:

    - - + + +
    +

    3.5. ServiceWorkerMessageEvent

    +
    [Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
    +interface ServiceWorkerMessageEvent : Event {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +
    dictionary ServiceWorkerMessageEventInit#dictdef-serviceworkermessageevent-serviceworkermessageeventinitReferenced in:3.5. ServiceWorkerMessageEvent : EventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +

    Service workers define the message event that extends the message event defined in [HTML] to allow setting a ServiceWorker object as the source of the message. For the message event, service workers use the ServiceWorkerMessageEvent#serviceworkermessage-event-interfaceReferenced in:3.5. ServiceWorkerMessageEvent (2)3.6. Events4.2.4. postMessage(message, transfer) interface.

    +
    +

    3.5.1. event.data

    +

    The data#serviceworkermessage-event-data-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.1. event.data4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    +
    +

    3.5.2. event.origin

    +

    The origin#serviceworkermessage-event-origin-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.2. event.origin4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker’s environment settings object from which the message is sent.

    +
    +
    +

    3.5.3. event.lastEventId

    +

    The lastEventId#serviceworkermessage-event-lasteventid-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.3. event.lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    +
    +

    3.5.4. event.source

    +

    The source#serviceworkermessage-event-source-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.4. event.source4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the ServiceWorker object whose associated service worker the message is sent from.

    +
    +
    +

    3.5.5. event.ports

    +

    The ports#serviceworkermessage-event-ports-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.5. event.ports4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

    +
    +
    +
    +

    3.6. Events

    +

    The following event is dispatched on ServiceWorker object:

    +
    - - - - - - + + - - - - - - -
    Event nameInterfaceDispatched when…
    Event name + Interface + Dispatched when…
    statechangeEventThe state attribute of the ServiceWorker object is changed.
    - -

    The following events are dispatched on ServiceWorkerContainer object:

    - - + +
    statechange#service-worker-statechange-eventReferenced in:3.1.4. Event handler + Event + The state attribute of the ServiceWorker object is changed. +
    +

    The following event is dispatched on ServiceWorkerRegistration object:

    + - - - - - - + + - - - - - - - - - - - - - - - - -
    Event nameInterfaceDispatched when…
    Event name + Interface + Dispatched when…
    updatefoundEventThe service worker registration's installing worker changes (See step 4.6 of the Install algorithm).
    controllerchangeEventThe service worker client's active worker changes. (See step 1.10 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, navigator.serviceWorker.controller immediately reflects the active worker as the service worker that controls the service worker client.)
    errorErrorEventAny error occurred from the associated service workers.
    -
    - - - -

    Execution Context

    - -

    Example: Serving Cached Resources

    - -// caching.js -this.addEventListener("install", function(e) { - e.waitUntil( - // Open a cache of resources. - caches.open("shell-v1").then(function(cache) { - // Begins the process of fetching them. - // The coast is only clear when all the resources are ready. - return cache.addAll([ - "/app.html", - "/assets/v1/base.css", - "/assets/v1/app.js", - "/assets/v1/logo.png", - "/assets/v1/intro_video.webm" - ]); - }) - ); -}); - -this.addEventListener("fetch", function(e) { - // No "fetch" events are dispatched to the service worker until it - // successfully installs and activates. - - // All operations on caches are async, including matching URLs, so we use - // promises heavily. e.respondWith() even takes promises to enable this: - e.respondWith( - caches.match(e.request).then(function(response) { - return response || e.default(); - }).catch(function() { - return caches.match("/fallback.html"); - }) - ); -}); - - -

    ServiceWorkerGlobalScope

    - -[Global=(Worker,ServiceWorker), Exposed=ServiceWorker] -interface ServiceWorkerGlobalScope : WorkerGlobalScope { - readonly attribute Cache scriptCache; - + + updatefound#service-worker-registration-updatefound-eventReferenced in:3.2.7. Event handler + Event + The service worker registration’s installing worker changes. (See step 7 of the Install algorithm.) + +

    The following events are dispatched on ServiceWorkerContainer object:

    + + + + + + + +
    Event name + Interface + Dispatched when… +
    controllerchange#service-worker-container-controllerchange-eventReferenced in:3.4.6. Event handlers + Event + The service worker client’s active worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, navigator.serviceWorker.controller immediately reflects the active worker as the service worker that controls the service worker client.) +
    message#service-worker-container-message-eventReferenced in:3.4.6. Event handlers3.5. ServiceWorkerMessageEvent (2)4.2.4. postMessage(message, transfer) + ServiceWorkerMessageEvent + When it receives a message. +
    error#service-worker-container-error-eventReferenced in:3.4.6. Event handlers + ErrorEvent + Any error occurred from the associated service workers. +
    +
    +
    +
    +

    4. Execution Context

    +
    + Serving Cached Resources: +
    // caching.js
    +this.addEventListener("install", function(e) {
    +  e.waitUntil(
    +    // Open a cache of resources.
    +    caches.open("shell-v1").then(function(cache) {
    +      // Begins the process of fetching them.
    +      // The coast is only clear when all the resources are ready.
    +      return cache.addAll([
    +        "/app.html",
    +        "/assets/v1/base.css",
    +        "/assets/v1/app.js",
    +        "/assets/v1/logo.png",
    +        "/assets/v1/intro_video.webm"
    +      ]);
    +    })
    +  );
    +});
    +
    +this.addEventListener("fetch", function(e) {
    +  // No "fetch" events are dispatched to the service worker until it
    +  // successfully installs and activates.
    +
    +  // All operations on caches are async, including matching URLs, so we use
    +  // promises heavily. e.respondWith() even takes promises to enable this:
    +  e.respondWith(
    +    caches.match(e.request).then(function(response) {
    +      return response || fetch(e.request);
    +    }).catch(function() {
    +      return caches.match("/fallback.html");
    +    })
    +  );
    +});
    +
    +
    +

    4.1. ServiceWorkerGlobalScope

    +
    [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
    +interface ServiceWorkerGlobalScope : WorkerGlobalScope {
       // A container for a list of Client objects that correspond to
       // browsing contexts (or shared workers) that are on the origin of this SW
    -  readonly attribute Clients clients;
    -  readonly attribute ServiceWorkerRegistration registration;
    +  [SameObject] readonly attribute Clients clients;
    +  [SameObject] readonly attribute ServiceWorkerRegistration registration;
     
    -  Promise<void> skipWaiting();
    +  [NewObject] Promise<void> skipWaiting();
     
    -  attribute EventHandler oninstall;
    -  attribute EventHandler onactivate;
    -  attribute EventHandler onfetch;
    -  attribute EventHandler onbeforeevicted;
    -  attribute EventHandler onevicted;
    +  attribute EventHandler oninstall;
    +  attribute EventHandler onactivate;
    +  attribute EventHandler onfetch;
    +  attribute EventHandler onforeignfetch;
     
    -  // The event.source of these MessageEvents are instances of Client
    -  attribute EventHandler onmessage;
    +  // event
    +  attribute EventHandler onmessage; // event.source of the message events is Client object
     
    -  // close() method inherited from WorkerGlobalScope should not be accessible.
    +  // close() method inherited from WorkerGlobalScope should not be accessible.
     };
    -
    -
    -    

    A ServiceWorkerGlobalScope object represents the global execution context of a service worker. A ServiceWorkerGlobalScope object has an associated service worker (a service worker).

    -

    ServiceWorkerGlobalScope object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

    - -

    The close() method inherited from WorkerGlobalScope, when called on the context object, should throw an "InvalidAccessError" exception.

    - - -

    scriptCache

    - -

    scriptCache must return a Cache object that represents the storage for scripts that are cached as part of the service worker installation.

    -
    - -

    clients

    - -

    clients attribute must return the Clients object.

    -
    - -

    registration

    - - The registration attribute must return the ServiceWorkerRegistration object that represents the service worker's containing service worker registration.

    -
    - - -

    skipWaiting()

    - -

    The skipWaiting() method allows this service worker to progress from the registration's waiting position to active even while service worker clients are using the registration.

    - -

    skipWaiting() method must run these steps or their equivalent:

    - - +
    +

    A ServiceWorkerGlobalScope#service-worker-global-scope-interfaceReferenced in:3.1.3. postMessage(message, transfer) (2)3.2.5. update()4.1. ServiceWorkerGlobalScope (2) (3) (4)4.1.4. Event handlers4.3. Clients4.4.1. event.waitUntil(f)4.9. Events6.3.2. importScripts(urls)8.3. Define Event Handler8.4. Request Functional Event DispatchRun Service Worker object represents the global execution context of a service worker. A ServiceWorkerGlobalScope object has an associated service worker#dfn-service-worker-global-scope-service-workerReferenced in:3.1.3. postMessage(message, transfer)3.2.5. update()4.1.2. registration4.2.4. postMessage(message, transfer)4.2.8. navigate(url) (2)4.3.1. get(id)4.3.2. matchAll(options) (2)4.3.3. openWindow(url)4.3.4. claim() (2) (3) (4) (5)4.5.1. event.registerForeignFetch(options)4.9. Events (2) (3) (4)6.3.2. importScripts(urls)Run Service Worker (a service worker).

    +

    ServiceWorkerGlobalScope object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

    +

    The close() method inherited from WorkerGlobalScope, when called on the context object, should throw an "InvalidAccessError" exception.

    +
    +

    4.1.1. clients

    +

    clients#service-worker-global-scope-clients-attributeReferenced in:4.1. ServiceWorkerGlobalScope4.1.1. clients attribute must return the Clients object that is associated with the context object.

    +
    +
    +

    4.1.2. registration

    +

    The registration#service-worker-global-scope-scope-attributeReferenced in:4.1. ServiceWorkerGlobalScope4.1.2. registration attribute must return the ServiceWorkerRegistration object that represents the service worker’s containing service worker registration.

    +
    +
    +

    4.1.3. skipWaiting()

    +

    The skipWaiting() method allows this service worker to progress from the registration’s waiting position to active even while service worker clients are using the registration.

    +

    skipWaiting()#service-worker-global-scope-skipwaiting-methodReferenced in:4.1. ServiceWorkerGlobalScope4.1.3. skipWaiting() (2) method must run these steps or their equivalent:

      -
    1. Let promise be a new promise.
    2. -
    3. Run the following substeps in parallel: +
    4. Let promise be a new promise. +
    5. + Run the following substeps in parallel: +
        +
      1. Set service worker’s skip waiting flag +
      2. + If service worker’s state is installed, then:
          -
        1. Set service worker's skip waiting flag
        2. -
        3. If service worker's state is installed, then: -
            -
          1. Run Activate algorithm, or its equivalent, passing service worker's registration as the argument.
          2. -
          -
        4. -
        5. Resolve promise with undefined.
        6. +
        7. Run Activate algorithm, or its equivalent, passing service worker’s registration as the argument.
        -
      3. -
      4. Return promise.
      5. -
      - - - - -

      Event handlers

      - -

      The following are the event handlers (and its corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    6. Resolve promise with undefined. + +
    7. Return promise. + + +
      +

      4.1.4. Event handlers

      +

      The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

      +
    8. event handlerevent handler event type
      oninstallinstall
      onactivateactivate
      onfetchfetch
      onbeforeevictedbeforeevicted
      onevictedevicted
      onmessagemessage
      + + + + + + + + +
      event handler + event handler event type +
      oninstall#service-worker-global-scope-oninstall-attributeReferenced in:3.1.2. state4.1. ServiceWorkerGlobalScope4.4.1. event.waitUntil(f) + install +
      onactivate#service-worker-global-scope-onactivate-attributeReferenced in:3.1.2. state4.1. ServiceWorkerGlobalScope4.4.1. event.waitUntil(f) + activate +
      onfetch#service-worker-global-scope-onfetch-attributeReferenced in:4.1. ServiceWorkerGlobalScope + fetch +
      onforeignfetch#dom-serviceworkerglobalscope-onforeignfetchReferenced in:4.1. ServiceWorkerGlobalScope + foreignfetch +
      onmessage#service-worker-global-scope-onmessage-attributeReferenced in:4.1. ServiceWorkerGlobalScope + message
      - -

      For onmessage event handler, ServiceWorkerGlobalScope objects act as if they had an implicit MessagePort associated with them. This port is part of a channel that is set up when the service worker is spun off to run, but it is not exposed. This object must never be garbage collected before the ServiceWorkerGlobalScope object. All messages received by that port must immediately be retargeted at the ServiceWorkerGlobalScope object. That is, an event named message using the MessageEvent interface is dispatched on ServiceWorkerGlobalScope object. The event.source of these MessageEvents are instances of Client.

      -
      - - -

      Client

      - -[Exposed=ServiceWorker] -interface Client { - readonly attribute USVString url; - readonly attribute ServiceWorkerRegistration? registration; - void postMessage(any message, optional sequence<Transferable> transfer); +
    +
    +
    +

    4.2. Client

    +
    [Exposed=ServiceWorker]
    +interface Client {
    +  readonly attribute USVString url;
    +  readonly attribute FrameType frameType;
    +  readonly attribute DOMString id;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
     };
     
     [Exposed=ServiceWorker]
    -interface WindowClient : Client {
    -  readonly attribute VisibilityState visibilityState;
    -  readonly attribute boolean focused;
    -  readonly attribute ContextFrameType frameType;
    -  Promise<WindowClient> focus();
    +interface WindowClient : Client {
    +  readonly attribute VisibilityState visibilityState;
    +  readonly attribute boolean focused;
    +  [NewObject] Promise<WindowClient> focus();
    +  [NewObject] Promise<WindowClient> navigate(USVString url);
     };
     
    -enum ContextFrameType {
    -  "top-level",
    -  "nested",
    -  "auxiliary",
    -  "none"
    +enum FrameType {
    +  "auxiliary",
    +  "top-level",
    +  "nested",
    +  "none"
     };
    -
    -    

    A Client object has an associated service worker client (a service worker client).

    - -

    This section will be updated as per SW #588.

    - - -

    Clients

    - -[Exposed=ServiceWorker] -interface Clients { +
    +

    A Client#client-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.2. Client (2) (3)4.3. Clients4.8. ExtendableMessageEvent (2)4.8.4. event.sourceCreate Client (2) object has an associated service worker client#dfn-service-worker-client-clientReferenced in:4.2.1. url4.2.2. frameType4.2.3. id4.2.4. postMessage(message, transfer)4.2.7. focus() (2) (3)4.2.8. navigate(url) (2) (3)Create ClientCreate Window Client (a service worker client).

    +

    A WindowClient#window-client-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.2. Client (2) (3) (4)4.3. ClientsCreate Window Client (2) object has an associated visibility state#dfn-service-worker-client-visibilitystateReferenced in:4.2.5. visibilityStateCreate Window Client, which is one of visibilityState attribute value.

    +

    A WindowClient object has an associated focus state#dfn-service-worker-client-focusstateReferenced in:4.2.6. focused4.2.7. focus()Create Window Client, which is either true or false (initially false).

    +
    +

    4.2.1. url

    +

    The url#client-url-attributeReferenced in:4.2. Client4.2.1. url attribute must return the context object’s associated service worker client’s serialized creation url.

    +
    +
    +

    4.2.2. frameType

    +

    The frameType#client-frametype-attributeReferenced in:4.2. Client4.2.2. frameType attribute must return the value (in FrameType#contextframetype-enumReferenced in:4.2. Client (2) enumeration) corresponding to the first matching statement, switching on service worker client’s frame type:

    +
    +
    auxiliary +
    + "auxiliary" +

    The window client’s global object’s browsing context is an auxiliary browsing context.

    +
    top-level +
    + "top-level" +

    The window client’s global object’s browsing context is a top-level browsing context.

    +
    nested +
    + "nested" +

    The window client’s global object’s browsing context is a nested browsing context.

    +
    none +
    "none" +
    +
    +
    +

    4.2.3. id

    +

    The id#client-id-attributeReferenced in:4.2. Client4.2.3. id attribute must return its associated service worker client’s id.

    +
    +
    +

    4.2.4. postMessage(message, transfer)

    +

    The postMessage(message, transfer)#client-postmessage-methodReferenced in:4.2. Client4.2.4. postMessage(message, transfer) method must run these steps or their equivalent:

    +
      +
    1. Let newPorts be an empty array. +
    2. Let transferMap be an empty association list of Transferable objects to placeholder objects. +
    3. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps. +
      2. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts. +
      +
    4. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps. +
    5. Let destination be the ServiceWorkerContainer object whose service worker client is the context object’s service worker client. +
    6. If destination is null, throw an "InvalidStateError" exception. +
    7. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. Let newOwner be the destination’s service worker client. +
      2. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts). +
      +
    8. Make newPorts into a read only array. +
    9. + Queue a task that runs the following steps: +
        +
      1. Create an event e that uses the ServiceWorkerMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action. +
      2. Let the data attribute of e be initialized to clonedMessage. +
      3. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object. +
      4. Let the source attribute of e be initialized to a ServiceWorker object, which represents the service worker associated with the global object specified by the incumbent settings object. +
      5. Let the ports attribute of e be initialized to newPorts. +
      6. Dispatch e at destination. +
      +

      The task must use the DOM manipulation task source, and, for those where the event loop specified by the target ServiceWorkerContainer object’s service worker client is a browsing context event loop, must be associated with the responsible document specified by that target ServiceWorkerContainer object’s service worker client.

      +
    +
    +
    +

    4.2.5. visibilityState

    +

    The visibilityState#client-visibilitystate-attributeReferenced in:4.2. Client4.2.5. visibilityState attribute must return the context object’s visibility state.

    +
    +
    +

    4.2.6. focused

    +

    The focused#client-focused-attributeReferenced in:4.2. Client4.2.6. focused attribute must return the context object’s focus state.

    +
    +
    +

    4.2.7. focus()

    +

    The focus()#client-focus-methodReferenced in:4.2. Client4.2.7. focus() method must run these steps or their equivalent:

    +
      +
    1. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception. +
    2. Let promise be a new promise. +
    3. + Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object’s associated service worker client’s global object’s browsing context. +
      2. Let visibilityState be null. +
      3. Let focusState be null. +
      4. + Queue a task task to run the following substeps on the context object’s associated service worker client’s responsible event loop using the user interaction task source: +
          +
        1. Run the focusing steps with browsingContext. +
        2. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
        3. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
        +
      5. Wait for task to have executed. +
      6. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with the context object’s associated service worker client, visibilityState and focusState as the arguments. +
      7. If windowClient’s focus state is true, resolve promise with windowClient. +
      8. Else, reject promise with a TypeError. +
      +
    4. Return promise. +
    +
    +
    +

    4.2.8. navigate(url)

    +

    The navigate()#client-navigate-methodReferenced in:4.2. Client4.2.8. navigate(url) method must run these steps or their equivalent:

    +
      +
    1. Let url be the result of parsing url with entry settings object’s API base URL. +
    2. If url is failure, return a promise rejected with a TypeError. +
    3. If url is about:blank, return a promise rejected with a TypeError. +
    4. If the context object’s associated service worker client’s active worker is not the incumbent settings object’s global object’s service worker, return a promise rejected with a TypeError. +
    5. Let promise be a new promise. +
    6. + Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object’s associated service worker client’s global object’s browsing context. +
      2. If browsingContext has discarded its Document, reject promise with a TypeError and abort these steps. +
      3. Let navigateFailed to false. +
      4. Let visibilityState be null. +
      5. Let focusState be null. +
      6. + Queue a task task to run the following substeps on the context object’s associated service worker client’s responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate browsingContext to url with replacement enabled and exceptions enabled. The source browsing context must be browsingContext. +
        2. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set navigateFailed to true. +
        3. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
        4. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
        +
      7. Wait for task to have executed (including its asynchronous steps). +
      8. If navigateFailed is true, reject promise with a TypeError and abort these steps. +
      9. + If browsingContext’s Window object’s environment settings object’s creation url’s origin is not the same as the service worker’s origin, then: +
          +
        1. Resolve promise with null. +
        2. Abort these steps. +
        +
      10. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with browsingContext’s Window object’s environment settings object, visibilityState and focusState as the arguments. +
      11. Resolve promise with windowClient. +
      +
    7. Return promise. +
    +
    +
    +
    +

    4.3. Clients

    +
    [Exposed=ServiceWorker]
    +interface Clients {
       // The objects returned will be new instances every time
    -  Promise<sequence<Client>?> getAll(optional ClientQueryOptions options);
    -  Promise<WindowClient> openWindow(USVString url);
    +  [NewObject] Promise<any> get(DOMString id);
    +  [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
    +  [NewObject] Promise<WindowClient?> openWindow(USVString url);
    +  [NewObject] Promise<void> claim();
     };
    -
    -dictionary ClientQueryOptions {
    -  boolean includeUncontrolled = false;
    -  ClientType type = "window";
    +
    +
    dictionary ClientQueryOptions#dictdef-clients-clientqueryoptionsReferenced in:4.3. Clients {
    +  boolean includeUncontrolled#dom-clientqueryoptions-includeuncontrolledReferenced in:4.3.2. matchAll(options) = false;
    +  ClientType type#dom-clientqueryoptions-typeReferenced in:4.3.2. matchAll(options) (2) (3) (4) = "window";
     };
    -
    -enum ClientType {
    -  "window",
    -  "worker",
    -  "sharedworker",
    -  "all"
    +
    +
    enum ClientType#enumdef-clients-clienttypeReferenced in:4.3. Clients {
    +  "window",
    +  "worker",
    +  "sharedworker",
    +  "all"
     };
    -
    -    

    The Clients interface represents a container for a list of Client objects.

    - -

    getAll(options)

    -

    The getAll(options) method must run these steps or their equivalent:

    - +
    +

    The user agent must create a Clients#clients-interfaceReferenced in:4.1. ServiceWorkerGlobalScope4.1.1. clients4.3. Clients (2) object when a ServiceWorkerGlobalScope object is created and associate it with that object.

    +
    +

    4.3.1. get(id)

    +

    The get(id)#clients-get-methodReferenced in:4.3. Clients4.3.1. get(id) method must run these steps or their equivalent:

      -
    1. Let promise be a new promise.
    2. -
    3. Run these steps in parallel: +
    4. Let promise be a new promise. +
    5. + Run these substeps in parallel: +
        +
      1. + For each service worker client client whose origin is the same as the associated service worker’s origin:
          -
        1. Let clients be an empty array.
        2. -
        3. If the optional argument options is omitted, then: +
        4. + If client’s id is id, then: +
            +
          1. If client is not a secure context, reject promise with a "SecurityError" exception and abort these steps. +
          2. + If client is a window client, then:
              -
            1. For each service worker client client whose active worker is the associated service worker, in the most recently focused order for window clients: -
                -
              1. If client is a window client, add a WindowClient object that represents client to clients.
              2. -
              -
            2. -
            3. Resolve promise with clients.
            4. +
            5. Let browsingContext be client’s global object’s browsing context. +
            6. Let visibilityState be null. +
            7. Let focusState be null. +
            8. + Queue a task task to run the following substeps: +
                +
              1. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
              2. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
              +
            9. Wait for task to have executed. +
            10. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
            11. Resolve promise with windowClient and abort these steps.
            -
          3. -
          4. Else: +
          5. + Else:
              -
            1. Let targetClients be an empty array.
            2. -
            3. For each service worker client client whose origin is the same as the associated service worker's origin: -
                -
              1. If options.includeUncontrolled is false, then: -
                  -
                1. If client's active worker is the associated service worker, add client to targetClients.
                2. -
                -
              2. -
              3. Else: -
                  -
                1. Add client to targetClients.
                2. -
                -
              4. -
              -
            4. -
            5. Let matchedClients be an empty array.
            6. -
            7. For each service worker client client in targetClients, in the most recently focused order for window clients: -
                -
              1. If options.type is "window", and client is a window client, add a WindowClient object that represents client to matchedClients.
              2. -
              3. Else if options.type is "worker" and client is a dedicated worker client, add a Client object that represents client to matchedClients.
              4. -
              5. Else if options.type is "sharedworker" and clientis a shared worker client, add a Client object that represents client to matchedClients.
              6. -
              7. Else if options.type is "all", then: -
                  -
                1. If client is a window client, add a WindowClient object that represents client to matchedClients.
                2. -
                3. Else, add a Client object that represents client to matchedClients.
                4. -
                -
              -
            8. -
            9. Resolve promise with matchedClients.
            10. +
            11. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
            12. Resolve promise with clientObject and abort these steps.
            -
          6. +
          +
        +
      2. Resolve promise with undefined. +
      +
    6. Return promise. +
    +
    +
    +

    4.3.2. matchAll(options)

    +

    The matchAll(options)#clients-matchall-methodReferenced in:4.3. Clients4.3.2. matchAll(options) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let targetClients be an empty array. +
      2. + For each service worker client client whose origin is the same as the associated service worker’s origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop. +
        2. + If options.includeUncontrolled is false, then: +
            +
          1. If client’s active worker is the associated service worker, add client to targetClients. +
          +
        3. + Else: +
            +
          1. Add client to targetClients. +
        -
      3. -
      4. Return promise.
      5. -
      - -

      This section will be updated as per SW #588.

      - - -

      openWindow(url)

      -

      The openWindow(url) method must run these steps or their equivalent:

      - -
        -
      1. Let url be the result of parsing url with entry settings object's API base URL.
      2. -
      3. If url is failure, return a promise rejected with a TypeError.
      4. -
      5. If this algorithm is not allowed to show a popup, return a promise rejected with a "InvalidAccessError" exception.
      6. -
      7. Let promise be a new promise.
      8. -
      9. Run these steps in parallel: +
      10. Let matchedClients be an empty array. +
      11. + For each service worker client client in targetClients, in the most recently focused order for window clients:
          -
        1. Let newContext be a new top level browsing context
        2. -
        3. If url is about:blank, then: - +
        4. + If options.type is "window", and client is a window client, then: +
            +
          1. Let browsingContext be client’s global object’s browsing context. +
          2. Let visibilityState be null. +
          3. Let focusState be null. +
          4. + Queue a task task to run the following substeps on client’s responsible event loop using the user interaction task source:
              -
            1. queue a task to fire a simple event named load at newContext's Window object, with target override set to newContext's Window object's Document object.
            2. +
            3. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
            4. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument.
            -
          5. Otherwise: +
          6. + Wait for task to have executed. +

            Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

            +
          7. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
          8. Add windowClient to matchedClients. +
          +
        5. + Else if options.type is "worker" and client is a dedicated worker client, or options.type is "sharedworker" and client is a shared worker client, then: +
            +
          1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
          2. Add clientObject to matchedClients. +
          +
        6. + Else if options.type is "all", then: +
            +
          1. + If client is a window client, then:
              -
            1. navigate newContext to url, with exceptions enabled and replacement enabled.
            2. +
            3. Let browsingContext be client’s global object’s browsing context. +
            4. Let visibilityState be null. +
            5. Let focusState be null. +
            6. + Queue a task task to run the following substeps on client’s responsible event loop using the user interaction task source: +
                +
              1. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
              2. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
              +
            7. + Wait for task to have executed. +

              Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

              +
            8. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
            9. Add windowClient to matchedClients.
            -
          2. -
          3. If the origin of url is not client's origin, then: +
          4. + Else:
              -
            1. Resolve promise with null.
            2. -
            3. Abort these steps.
            4. +
            5. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
            6. Add clientObject to matchedClients.
            -
          5. -
          6. Let client be a new WindowClient representing newContext
          7. -
          8. Resolve promise with client.
          9. +
        -
      12. -
      13. Return promise.
      14. +
      15. Resolve promise with matchedClients. +
      +
    3. Return promise.
    - -

    Creating a client is yet to be defined.

    - - - - - - -

    ExtendableEvent

    - -[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker] -interface ExtendableEvent : Event { - void waitUntil(Promise<any> f); -}; - -dictionary ExtendableEventInit : EventInit { - // Defined for the forward compatibility across the derived events -}; - - -

    Service workers have two lifecycle events, install and activate. Service workers use the ExtendableEvent interface for activate event and the InstallEvent interface, which inherits from the ExtendableEvent interface, for install event. Service worker extensions that define event handlers may also use the ExtendableEvent interface.

    - -

    An ExtendableEvent object has an associated extend lifetime promises (an array of promises). It is initially set to null.

    - -

    The service worker should not be terminated until the result of waiting for all of the extend lifetime promises has been settled. However, the user agent may impose a time limit to this lifetime extension.

    - - -

    event.waitUntil(f)

    - -

    waitUntil(f) method, extends the lifetime of the event. When called in oninstall, it delays treating the installing worker as installed (i.e. a waiting worker) until the passed promise resolves successfully. This is primarily used to ensure that a service worker is not considered installed (i.e. a waiting worker) until all of the core caches it depends on are populated. When called in onactivate, it delays treating the active worker as activated until the passed promise resolves successfully. This is primarily used to ensure that any functional events are not dispatched to the ServiceWorkerGlobalScope object that represents the service worker until it upgrades database schemas and deletes the outdated cache entries. Service worker extensions that define event handlers will define their own behaviours, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

    - -

    waitUntil(f) method must run these steps or their equivalent:

    - +
    +
    +

    4.3.3. openWindow(url)

    +

    The openWindow(url)#clients-openwindow-methodReferenced in:4.3. Clients4.3.3. openWindow(url) method must run these steps or their equivalent:

      -
    1. If the active function is not the callback of the event handler whose type is the context object's type value, then: +
    2. Let url be the result of parsing url with entry settings object’s API base URL. +
    3. If url is failure, return a promise rejected with a TypeError. +
    4. If url is about:blank, return a promise rejected with a TypeError. +
    5. If this algorithm is not allowed to show a popup, return a promise rejected with an "<InvalidAccessError" exception. +
    6. Let promise be a new promise. +
    7. + Run these substeps in parallel: +
        +
      1. Let newContext be a new top-level browsing context. +
      2. Let openWindowFailed to false. +
      3. Let visibilityState be null. +
      4. Let focusState be null. +
      5. + Queue a task task to run the following substeps on newContext’s Window object’s environment settings object’s responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate newContext to url, with exceptions enabled and replacement enabled. +
        2. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set openWindowFailed to true. +
        3. Set visibilityState to newContext’s active document’s visibilityState attribute value. +
        4. Set focusState to the result of running the has focus steps with newContext’s active document as the argument. +
        +
      6. Wait for task to have executed (including its asynchronous steps). +
      7. If openWindowFailed is true, reject promise with a TypeError and abort these steps. +
      8. + If newContext’s Window object’s environment settings object’s creation url’s origin is not the same as the service worker’s origin, then:
          -
        1. Throw an "InvalidStateError" exception.
        2. -
        3. Abort these steps.
        4. +
        5. Resolve promise with null. +
        6. Abort these steps.
        -
      9. -
      10. Add f to extend lifetime promises.
      11. +
      12. Let client be the result of running Create Window Client algorithm, or its equivalent, with newContext’s Window object’s environment settings object, visibilityState and focusState as the arguments. +
      13. Resolve promise with client. +
      +
    8. Return promise.
    - - - - - -

    InstallEvent

    - -[Constructor(DOMString type, optional InstallEventInit eventInitDict), Exposed=ServiceWorker] -interface InstallEvent : ExtendableEvent { - readonly attribute ServiceWorker? activeWorker; -}; - -dictionary InstallEventInit : EventInit { - ServiceWorker activeWorker; -}; - -
    - - -

    FetchEvent

    - -[Constructor(DOMString type, optional FetchEventInit eventInitDict), Exposed=ServiceWorker] -interface FetchEvent : Event { - readonly attribute Request request; - readonly attribute Client client; - readonly attribute boolean isReload; - - void respondWith((Response or Promise<Response>) r); - Promise<Response> forwardTo(USVString url); - Promise<Response> default(); +
    +
    +

    4.3.4. claim()

    +

    The claim()#clients-claim-methodReferenced in:4.3. Clients4.3.4. claim() method must run these steps or their equivalent:

    +
      +
    1. If the service worker is not an active worker, return a promise rejected with an "InvalidStateError" exception. +
    2. Let promise be a new promise. +
    3. + Run the following substeps in parallel: +
        +
      1. + For each service worker client client whose origin is the same as the service worker’s origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop. +
        2. Let registration be the result of running Match Service Worker Registration algorithm passing client’s creation url as the argument. +
        3. If registration is not the service worker’s containing service worker registration, continue to the next iteration of the loop. +
        4. + If client’s active worker is not the service worker, then: +
            +
          1. Invoke Handle Service Worker Client Unload with client as the argument. +
          2. Set client’s active worker to service worker. +
          3. Invoke Notify Controller Change algorithm with client as the argument. +
          +
        +
      2. Resolve promise with undefined. +
      +
    4. Return promise. +
    +
    +
    +
    +

    4.4. ExtendableEvent

    +
    [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableEvent : Event {
    +  void waitUntil(Promise<any> f);
     };
    -
    -dictionary FetchEventInit : EventInit {
    -  Request request;
    -  Client client;
    -  boolean isReload;
    +
    +
    dictionary ExtendableEventInit#dictdef-extendableeventinitReferenced in:4.4. ExtendableEvent4.5. InstallEvent4.6. FetchEvent4.7. ForeignFetchEvent4.8. ExtendableMessageEvent : EventInit {
    +  // Defined for the forward compatibility across the derived events
     };
    -
    -
    -    

    Each event using FetchEvent interface has the following associated flag that is initially unset: +

    +

    An ExtendableEvent#extendable-event-interfaceReferenced in:4.4. ExtendableEvent (2) (3) (4)4.5. InstallEvent4.6. FetchEvent (2)4.7. ForeignFetchEvent (2)4.8. ExtendableMessageEvent (2)4.9. Events8.2. Define Functional EventActivate object has an associated extend lifetime promises#dfn-extend-lifetime-promisesReferenced in:4.4.1. event.waitUntil(f) (2) (3) (4)InstallActivate (an array of promises). It is initially set to null.

    +

    Service workers have two lifecycle events, install and activate. Service workers use the ExtendableEvent interface for activate event and install event.

    +

    Service worker extensions that define event handlers may also use or extend the ExtendableEvent interface.

    +
    +

    4.4.1. event.waitUntil(f)

    +

    waitUntil(f) method extends the lifetime of the event.

    +

    waitUntil(f)#extendable-event-waituntil-methodReferenced in:3.1.2. state (2)4.4. ExtendableEvent4.4.1. event.waitUntil(f) (2) (3)4.8. ExtendableMessageEvent method must run these steps or their equivalent:

    +
      +
    1. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    2. Add f to extend lifetime promises. +
    +

    In the task task in which the steps of waitUntil(f) is running, the user agent must run these steps or their equivalent:

    +
      +
    1. Let extendLifetimePromises be an empty array. +
    2. + For each event listener invoked: +
        +
      1. Let eventObject be the first argument passed to this event listener. +
      2. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
      +
    3. Do not terminate the service worker whose responsible event loop is running task until waiting for all of extendLifetimePromises settles. +
    +

    However, the user agent may impose a time limit to this lifetime extension.

    +

    Service workers and extensions that define event handlers may define their own behaviors, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

    +

    Service workers define the following behaviors for install event and activate event:

    -

    - - -

    event.respondWith(r)

    - -

    When event.respondWith(r) method is invoked, the argument, r, must resolve with a Response, else a network error is returned to Fetch. If the request is a top-level navigation and the return value is a Response whose type attribute is "opaque" (i.e., an opaque response body), a network error is returned to Fetch. The final URL of all successful (non network-error) responses is the requested URL. Renderer-side security checks about tainting for cross-origin content are tied to the transparency (or opacity) of the Response body, not URLs.

    +
    +
    +
    +

    4.5. InstallEvent

    +
    [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface InstallEvent#installevent-installeventReferenced in:4.5. InstallEvent4.9. EventsInstall : ExtendableEvent {
    +  void registerForeignFetch(ForeignFetchOptions options);
    +};
     
    -      

    respondWith(r) method must run these steps or their equivalent:

    - +dictionary ForeignFetchOptions#dictdef-installevent-foreignfetchoptionsReferenced in:4.5. InstallEvent { + required sequence<USVString> scopes#dom-foreignfetchoptions-scopesReferenced in:4.5.1. event.registerForeignFetch(options) (2); + required sequence<USVString> origins#dom-foreignfetchoptions-originsReferenced in:4.5.1. event.registerForeignFetch(options) (2); +}; +
    +
    +

    4.5.1. event.registerForeignFetch(options)

    +

    registerForeignFetch(options) registers this service worker to handle foreign fetches from certain origins for certain sub scopes.

    +

    registerForeignFetch(options)#dom-installevent-registerforeignfetchReferenced in:4.5. InstallEvent4.5.1. event.registerForeignFetch(options) (2) method must run these steps or their equivalent:

      -
    1. If the active function is not the callback of the event handler whose type is fetch, then: -
        -
      1. Throw an "InvalidStateError" exception.
      2. -
      3. Abort these steps.
      4. -
      -
    2. -
    3. If the respond-with entered flag is set, then: -
        -
      1. Throw an "InvalidStateError" exception.
      2. -
      3. Abort these steps.
      4. -
      -
    4. -
    5. Set the stop propagation flag and stop immediate propagation flag.
    6. -
    7. Set the respond-with entered flag.
    8. -
    9. Set the wait to respond flag.
    10. -
    11. Let responsePromise be null.
    12. -
    13. If r is a Response object, then: +
    14. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    15. If options.origins is empty throw a TypeError and abort these steps. +
    16. Let originURLs be an empty list of URLs. +
    17. + If the value of options.origins is not a single string equal to a single U+002A ASTERISK character (*): +
        +
      1. + For each origin in options.origins:
          -
        1. Set responsePromise to a promise resolved with r.
        2. +
        3. If the value of origin is not an absolute URL, throw a TypeError and abort these steps. +
        4. Add the result of parsing origin to originURLs.
        -
      2. -
      3. Else: +
      +
    18. If options.scopes is empty throw a TypeError and abort these steps. +
    19. Let scopeString be the incumbent settings object’s global object’s service worker’s containing service worker registration’s scope url, serialized. +
    20. Let subScopeURLs be an empty list of URLs. +
    21. + For each subScope in options.scopes: +
        +
      1. Let subScopeURL be the result of parsing subScope with entry settings object’s API base URL. +
      2. If subScopeURL is failure, throw a TypeError and abort these steps. +
      3. Let subScopeString be the serialized subScopeURL. +
      4. If subScopeString does not start with scopeString, throw a TypeError and abort these steps. +
      5. Add subScopeURL to subScopeURLs. +
      +
    22. Set this service worker’s list of foreign fetch scopes to subScopeURLs. +
    23. Set this service worker’s list of foreign fetch origins to originURLs. +
    +
    +
    +
    +

    4.6. FetchEvent

    +
    [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface FetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +  readonly attribute DOMString? clientId;
    +  readonly attribute boolean isReload;
    +
    +  void respondWith(Promise<Response> r);
    +};
    +
    +
    dictionary FetchEventInit#dictdef-fetchevent-fetcheventinitReferenced in:4.6. FetchEvent : ExtendableEventInit {
    +  required Request request;
    +  DOMString? clientId = null;
    +  boolean isReload = false;
    +};
    +
    +

    Service workers have an essential functional event fetch. For fetch event, service workers use the FetchEvent#fetch-event-interfaceReferenced in:4.6. FetchEvent (2) (3)4.9. Events (2)Handle Fetch interface which extends the ExtendableEvent interface.

    +

    Each event using FetchEvent interface has an associated potential response#fetchevent-potential-responseReferenced in:4.6.4. event.respondWith(r)Handle Fetch (a response), initially set to null, and the following associated flags that are initially unset:

    + +

    +
    +

    4.6.1. event.request

    +

    request#fetch-event-request-attributeReferenced in:4.6. FetchEvent4.6.1. event.requestHandle FetchHandle Foreign Fetch attribute must return the value it was initialized to.

    +
    +
    +

    4.6.2. event.clientId

    +

    clientId#fetch-event-clientid-attributeReferenced in:4.6. FetchEvent4.6.2. event.clientIdHandle Fetch attribute must return the value it was initialized to. When an event is created the attribute must be initialized to null.

    +
    +
    +

    4.6.3. event.isReload

    +

    isReload#fetch-event-isreload-attributeReferenced in:4.6. FetchEvent4.6.3. event.isReloadHandle Fetch attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

    +

    Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

    +
    +
    +

    4.6.4. event.respondWith(r)

    +

    Developers can set the argument r with either a promise that resolves with a Response object or a Response object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

    +

    respondWith(r)#fetch-event-respondwith-methodReferenced in:4.6. FetchEvent4.6.4. event.respondWith(r)6.4. Cross-Origin Resources and CORS method must run these steps or their equivalent:

    +
      +
    1. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    2. + If the respond-with entered flag is set, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    3. Set the stop propagation flag and stop immediate propagation flag. +
    4. Set the respond-with entered flag. +
    5. Set the wait to respond flag. +
    6. + Run the following substeps in parallel: +
        +
      1. Wait until r settles. +
      2. + If r rejected, then:
          -
        1. Set responsePromise to r.
        2. +
        3. Set the respond-with error flag.
        -
      3. -
      4. Run the following substeps in parallel: +
      5. + If r resolved with response, then:
          -
        1. Wait until responsePromise settles.
        2. -
        3. If responsePromise rejected, then: +
        4. + If response is a Response object, then: +
            +
          1. + If response is disturbed or locked, then:
              -
            1. Set the respond-with error flag.
            2. +
            3. Set the respond-with error flag.
            -
          2. -
          3. If responsePromise resolved with response, then: +
          4. + Else:
              -
            1. If response is a Response object, then: -
                -
              1. Let request be the context object's request attribute value.
              2. -
              3. If response.type is "opaque", and request's associated request is a client request, set the respond-with error flag.
              4. -
              5. If response's body is non-null, then: -
                  -
                1. If response's used flag is set, set the respond-with error flag.
                2. -
                3. Set response's used flag.
                4. -
                -
              6. -
              -
            2. -
            3. Else: -
                -
              1. Set the respond-with error flag.
              2. -
              -

              If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 19.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 20.1.)

              -
            4. +
            5. Let potentialResponse be a copy of response’s associated response, except for its body. +
            6. + If response’s body is non-null, run these substeps: +
                +
              1. Set potentialResponse’s body to response’s body. +
              2. Let dummyStream be an empty ReadableStream object. +
              3. Set response’s body to a new body whose stream is dummyStream. +
              4. Let reader be the result of getting a reader from dummyStream. +
              5. Read all bytes from dummyStream with reader. +
              +

              These substeps are meant to produce the observable equivalent of "piping" response’s body’s stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse’s body’s stream is now equal to what used to be response’s, if response’s original body is non-null.

              +

              These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

              +
            7. Set the potential response to potentialResponse.
            -
          5. - -
          6. Unset the wait to respond flag.
          7. +
          +
        5. + Else: +
            +
          1. Set the respond-with error flag. +
          +

          If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 22.1.)

        -
      6. +
      7. Unset the wait to respond flag. +
    - - - - -

    event.default()

    +
    +
    +
    +

    4.7. ForeignFetchEvent

    +
    [Constructor(DOMString type, ForeignFetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ForeignFetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +
    +  void respondWith(Promise<ForeignFetchResponse> r);
    +};
     
    -      

    The invocation of event.default() method performs a fetch using event.request. event.request represents the original request from the controlled service worker client. During the execution, the original request is not altered (except the skip service worker flag), and thus event.default() fetches the original request through the UA's HTTP stack. event.default() returns a promise, which resolves with a Response object, that can be an argument to the event.respondWith(r) method.

    +dictionary ForeignFetchEventInit#dictdef-foreignfetchevent-foreignfetcheventinitReferenced in:4.7. ForeignFetchEvent : ExtendableEventInit { + required Request request; +}; -

    default() method must run these steps or their equivalent:

    - -
      -
    1. If event's dispatch flag is unset, then: +dictionary ForeignFetchResponse#dictdef-foreignfetchevent-foreignfetchresponseReferenced in:4.7. ForeignFetchEvent4.7.2. event.respondWith(r) { + required Response response#dom-foreignfetchresponse-responseReferenced in:4.7.2. event.respondWith(r) (2) (3) (4) (5); + USVString origin#dom-foreignfetchresponse-originReferenced in:4.7.2. event.respondWith(r); + sequence<ByteString> headers#dom-foreignfetchresponse-headersReferenced in:4.7.2. event.respondWith(r); +}; +
    +

    Service workers have a functional event foreignfetch. For foreignfetch events, service workers use the ForeignFetchEvent#foreignfetchevent-foreignfetcheventReferenced in:4.7. ForeignFetchEvent (2) (3)Handle Foreign Fetch interface which extends the ExtendableEvent interface.

    +

    Each event using ForeignFetchEvent interface has an associated potential response#foreignfetchevent-potential-responseReferenced in:4.7.2. event.respondWith(r)Handle Foreign Fetch (2) (3) (4) (5) (a response), initially set to null, an associated origin#foreignfetchevent-originReferenced in:4.7.2. event.respondWith(r)Handle Foreign Fetch (2) (a URL), initially set to null, an associated list of exposed headers#foreignfetchevent-list-of-exposed-headersReferenced in:4.7.2. event.respondWith(r)Handle Foreign Fetch (2) (whose element type is a byte string), initially set to an empty list, and the following associated flags that are initially unset:

    + +

    +
    +

    4.7.1. event.request

    +

    request#dom-foreignfetchevent-requestReferenced in:4.7. ForeignFetchEvent4.7.1. event.request attribute must return the value it was initialized to.

    +
    +
    +

    4.7.2. event.respondWith(r)

    +

    Developers can set the argument r with either a promise that resolves with a Response object or a Response object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

    +

    respondWith(r)#dom-foreignfetchevent-respondwithReferenced in:4.7. ForeignFetchEvent4.7.2. event.respondWith(r) method must run these steps or their equivalent:

    +
      +
    1. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    2. + If the respond-with entered flag is set, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    3. Set the stop propagation flag and stop immediate propagation flag. +
    4. Set the respond-with entered flag. +
    5. Set the wait to respond flag. +
    6. + Run the following substeps in parallel: +
        +
      1. Wait until r settles. +
      2. + If r rejected, then:
          -
        1. Return a promise rejected with a "InvalidStateError" exception.
        2. +
        3. Set the respond-with error flag.
        -
      3. -
      4. Let promise be a new promise.
      5. -
      6. Run the following substeps in parallel: +
      7. + If r resolved with response, then:
          -
        1. Let r be the context object's request attribute value.
        2. -
        3. If r's body is non-null, then: -
            -
          1. If r's used flag is set, then: -
              -
            1. Reject promise with a TypeError.
            2. -
            3. Abort these steps.
            4. -
            -
          2. -
          3. Set r's used flag.
          4. -
          -
        4. -
        5. Let request be r's associated request.
        6. -
        7. Set request's skip service worker flag and request's synchronous flag.
        8. -
        9. Let response be the result of running fetch with request as its argument.
        10. -
        11. If response is a network error, then: +
        12. + If response is a ForeignFetchResponse, then: +
            +
          1. Set the event’s origin to response.origin. +
          2. Set the event’s list of exposed headers to response.headers. +
          3. + If response.response is disturbed or locked, then:
              -
            1. Reject promise with a TypeError.
            2. +
            3. Set the respond-with error flag.
            -
          4. -
          5. Else: +
          6. + Else:
              -
            1. Resolve promise with a new Response object associated with response.
            2. +
            3. Let potentialResponse be a copy of response.response's associated response, except for its body. +
            4. + If response.response's body is non-null, run these substeps: +
                +
              1. Set potentialResponse’s body to response.response's body. +
              2. Let dummyStream be an empty ReadableStream object. +
              3. Set response.response's body to a new body whose stream is dummyStream. +
              4. Let reader be the result of getting a reader from dummyStream. +
              5. Read all bytes from dummyStream with reader. +
              +

              These substeps are meant to produce the observable equivalent of "piping" response’s body’s stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse’s body’s stream is now equal to what used to be response’s, if response’s original body is non-null.

              +

              These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

              +
            5. Set the potential response to potentialResponse.
            -
          7. +
          +
        13. + Else: +
            +
          1. Set the respond-with error flag. +
          +

          If the respond-with error flag is set, a network error is returned to Fetch through Handle Foreign Fetch algorithm. (See the step 21.1.) Otherwise, a filtered version of response is returned to Fetch through Handle Foreign Fetch algorithm. (See the step 22.1.)

        -
      8. -
      9. Return promise.
      10. +
      11. Unset the wait to respond flag. +
    - - - - -

    event.isReload

    - -

    isReload attribute must return true if event was dispatched with the user's intention for the page reload, and false otherwise. Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

    -
    - - - -

    Events

    - -

    The following events are dispatched on ServiceWorkerGlobalScope object:

    - - + + +
    +

    4.8. ExtendableMessageEvent

    +
    [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableMessageEvent : ExtendableEvent {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +
    dictionary ExtendableMessageEventInit#dictdef-extendablemessageevent-extendablemessageeventinitReferenced in:4.8. ExtendableMessageEvent : ExtendableEventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (Client or ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +

    Service workers define the extendable message event that extends the message event defined in [HTML] to allow extending the lifetime of the event. For the message event, service workers use the ExtendableMessageEvent#extendablemessage-event-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.8. ExtendableMessageEvent (2)4.9. Events interface which extends the ExtendableEvent interface.

    +
    +

    4.8.1. event.data

    +

    The data#extendablemessage-event-data-attributeReferenced in:3.1.3. postMessage(message, transfer)4.8. ExtendableMessageEvent4.8.1. event.data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    +
    +

    4.8.2. event.origin

    +

    The origin#extendablemessage-event-origin-attributeReferenced in:3.1.3. postMessage(message, transfer)4.8. ExtendableMessageEvent4.8.2. event.origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker client that sent the message.

    +
    +
    +

    4.8.3. event.lastEventId

    +

    The lastEventId#extendablemessage-event-lasteventid-attributeReferenced in:4.8. ExtendableMessageEvent4.8.3. event.lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    +
    +

    4.8.4. event.source

    +

    The source#extendablemessage-event-source-attributeReferenced in:3.1.3. postMessage(message, transfer) (2)4.8. ExtendableMessageEvent4.8.4. event.source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the Client object from which the message is sent.

    +
    +
    +

    4.8.5. event.ports

    +

    The ports#extendablemessage-event-ports-attributeReferenced in:3.1.3. postMessage(message, transfer)4.8. ExtendableMessageEvent4.8.5. event.ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

    +
    +
    +
    +

    4.9. Events

    +

    The following events are dispatched on ServiceWorkerGlobalScope object:

    +
    - - - - - - + + - - - - - - - - - - - - - - - - -
    Event nameInterfaceDispatched when…
    Event name + Interface + Dispatched when…
    installInstallEvent[Lifecycle event] The service worker's containing service worker registration's installing worker changes. (See step 4.7.3 of the Install algorithm.)
    activateExtendableEvent[Lifecycle event] The service worker's containing service worker registration's active worker changes. (See step 1.11.3 of the Activate algorithm.)
    fetchFetchEvent[Functional event] Fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the Service Woker returns a response to Fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method or event.default() method. (A custom Response object can be another option.)
    - -

    Custom event types for beforeevicted and evicted should be added.

    -
    - - - -

    Caches

    -

    To allow authors to fully manage their content caches for offline use, the Window and the WorkerGlobalScope provide the caching methods largely conforming to ECMAScript 6 Map objects with additional convenience methods. An origin can have multiple, named Cache objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser's HTTP cache.

    - - -

    Constructs

    - -

    A fetching record is a Record {[[key]], [[value]]} where [[key]] is a Request and [[value]] is a Response.

    -

    A fetching record has an associated incumbent record (a fetching record). It is initially set to null.

    -

    A request to response map is a List of fetching records.

    - -

    A name to cache map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a name of the Cache object and [[value]] is a Cache object.

    - -

    Each origin has an associated name to cache map.

    -
    - - -

    Understanding Cache Lifetimes

    - -

    The Cache instances are not part of the browser's HTTP cache. The Cache objects are exactly what authors have to manage themselves. The Cache objects do not get updated unless authors explicitly request them to be. The Cache objects do not expire unless authors delete the entries. The Cache objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

    -
    - - -

    self.caches

    -partial interface Window { -readonly attribute CacheStorage caches; + + install#service-worker-global-scope-install-eventReferenced in:2.1. Service Worker4.1.4. Event handlers4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f)Install + InstallEvent + [Lifecycle event] The service worker’s containing service worker registration’s installing worker changes. (See step 11.2 of the Install algorithm.) + + activate#service-worker-global-scope-activate-eventReferenced in:2.1. Service Worker4.1.4. Event handlers4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f)Activate + ExtendableEvent + [Lifecycle event] The service worker’s containing service worker registration’s active worker changes. (See step 15.2 of the Activate algorithm.) + + fetch#service-worker-global-scope-fetch-eventReferenced in:2.1. Service Worker2.5. Task Sources4.1.4. Event handlers4.6. FetchEvent (2)6.5. Implementer ConcernsHandle Fetch + FetchEvent + [Functional event] The http fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the service worker returns a response to the http fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method. (A custom Response object can be another option.) + + foreignfetch#service-worker-global-scope-foreignfetch-eventReferenced in:4.1.4. Event handlers4.7. ForeignFetchEvent (2)Handle Foreign Fetch + FetchEvent + [Functional event] The http fetch invokes Handle Foreign Fetch with request. As a result of performing Handle Foreign Fetch, the service worker returns a response to the http fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method. (A custom Response object can be another option.) + + message#service-worker-global-scope-message-eventReferenced in:3.1.3. postMessage(message, transfer)4.1.4. Event handlers4.8. ExtendableMessageEvent (2) + ExtendableMessageEvent + When it receives a message. + +
    +
    +
    +

    5. Caches

    +

    To allow authors to fully manage their content caches for offline use, the Window and the WorkerGlobalScope provide the asynchronous caching methods that open and manipulate Cache objects. An origin can have multiple, named Cache objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser’s HTTP cache.

    +
    +

    5.1. Constructs

    +

    A fetching record#dfn-fetching-recordReferenced in:5.1. Constructs (2) (3)5.4.2. matchAll(request, options) (2)5.4.4. addAll(requests) (2)5.4.5. put(request, response) (2)5.4.7. keys(request, options)Query CacheBatch Cache Operations (2) (3) is a Record {[[key]], [[value]]} where [[key]] is a Request and [[value]] is a Response.

    +

    A fetching record has an associated incumbent record#dfn-incumbent-recordReferenced in:5.4.2. matchAll(request, options)5.4.4. addAll(requests) (2)5.4.5. put(request, response) (2) (a fetching record). It is initially set to null.

    +

    A request to response map#dfn-request-to-response-mapReferenced in:5.4. Cache (2)5.4.2. matchAll(request, options) (2)5.4.4. addAll(requests) (2) (3) (4) (5)5.4.5. put(request, response) (2) (3) (4) (5)5.4.7. keys(request, options)6.6. PrivacyQuery CacheBatch Cache Operations (2) (3) (4) (5) (6) is a List of fetching records.

    +

    A name to cache map#dfn-name-to-cache-mapReferenced in:5.1. Constructs5.5. CacheStorage (2)5.5.1. match(request, options) (2)5.5.2. has(cacheName)5.5.3. open(cacheName) (2)5.5.4. delete(cacheName)5.5.5. keys()6.6. Privacy is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a name of the Cache object and [[value]] is a Cache object.

    +

    Each origin has an associated name to cache map.

    +
    +
    +

    5.2. Understanding Cache Lifetimes

    +

    The Cache instances are not part of the browser’s HTTP cache. The Cache objects are exactly what authors have to manage themselves. The Cache objects do not get updated unless authors explicitly request them to be. The Cache objects do not expire unless authors delete the entries. The Cache objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

    +
    +
    +

    5.3. self.caches

    +
    partial interface Window {
    +  [SameObject] readonly attribute CacheStorage caches;
     };
     
    -partial interface WorkerGlobalScope {
    -readonly attribute CacheStorage caches;
    +partial interface WorkerGlobalScope {
    +  [SameObject] readonly attribute CacheStorage caches;
     };
    -
    -    
    -    

    caches

    - -

    caches attribute must return a CacheStorage object that represents the name to cache map of the context object's environment settings object's origin.

    -
    - - - -

    Cache

    -[Exposed=(Window,Worker)] -interface Cache { -Promise<Response> match(RequestInfo request, optional CacheQueryOptions options); -Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options); -Promise<void> add(RequestInfo request); -Promise<void> addAll(sequence<RequestInfo> requests); -Promise<void> put(RequestInfo request, Response response); -Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options); -Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options); +
    +
    +

    5.3.1. caches

    +

    caches#global-caches-attributeReferenced in:5.3. self.caches#window-caches-attributeReferenced in:5.3. self.caches (2)5.3.1. caches5.4. Cache attribute must return the CacheStorage object that is associated with the context object.

    +
    +
    +
    +

    5.4. Cache

    +
    [Exposed=(Window,Worker)]
    +interface Cache {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<void> add(RequestInfo request);
    +  [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
    +  [NewObject] Promise<void> put(RequestInfo request, Response response);
    +  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
     };
    -
    -dictionary CacheQueryOptions {
    -boolean ignoreSearch = false;
    -boolean ignoreMethod = false;
    -boolean ignoreVary = false;
    -boolean prefixMatch = false;
    -DOMString cacheName;
    +
    +
    dictionary CacheQueryOptions#dictdef-cache-cachequeryoptionsReferenced in:5.4. Cache (2) (3) (4) (5)5.5. CacheStorageQuery Cache {
    +  boolean ignoreSearch#dom-cachequeryoptions-ignoresearchReferenced in:Query Cache = false;
    +  boolean ignoreMethod#dom-cachequeryoptions-ignoremethodReferenced in:Query Cache = false;
    +  boolean ignoreVary#dom-cachequeryoptions-ignorevaryReferenced in:Query Cache = false;
    +  DOMString cacheName#dom-cachequeryoptions-cachenameReferenced in:5.5.1. match(request, options) (2);
     };
    -
    -dictionary CacheBatchOperation {
    -DOMString type;
    -Request request;
    -Response response;
    -CacheQueryOptions options;
    +
    +
    dictionary CacheBatchOperation#dictdef-cache-cachebatchoperationReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations {
    +  DOMString type#dom-cachebatchoperation-typeReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations (2) (3) (4);
    +  Request request#dom-cachebatchoperation-requestReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations (2) (3) (4) (5);
    +  Response response#dom-cachebatchoperation-responseReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)Batch Cache Operations (2) (3) (4) (5);
    +  CacheQueryOptions options#dom-cachebatchoperation-optionsReferenced in:5.4.6. delete(request, options)Batch Cache Operations (2) (3);
     };
    -
    -    

    A Cache object represents a request to response map. Multiple separate objects implementing the Cache interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

    - -

    Cache objects are always enumerable via self.caches in insertion order (per ECMAScript 6 Map objects.)

    - - -

    match(request, options)

    - -

    match(request, options) method must run these steps or their equivalent:

    - - -
      -
    1. Let promise be a new promise.
    2. -
    3. Run these steps in parallel: -
        -
      1. Let p be the result of running the algorithm specified in matchAll(request, options) method with request and options as the arguments.
      2. -
      3. Wait until p settles.
      4. -
      5. If p rejects with an exception, then: -
          -
        1. Reject promise with that exception.
        2. -
        -
      6. -
      7. Else if p resolves with an array, responseArray, then: -
          -
        1. If responseArray is an empty array, then: -
            -
          1. Resolve promise with undefined.
          2. -
          -
        2. -
        3. Else: -
            -
          1. Resolve promise with the first element of responseArray.
          2. -
          -
        4. -
        -
      8. -
      -
    4. -
    5. Return promise.
    6. -
    -
    -
    - - -

    matchAll(request, options)

    - -

    matchAll(request, options) method must run these steps or their equivalent:

    - - +
    +

    A Cache#cache-interfaceReferenced in:4.9. Events (2)5. Caches (2)5.1. Constructs (2)5.2. Understanding Cache Lifetimes (2) (3) (4) (5)5.4. Cache (2) (3) (4)5.5. CacheStorage5.5.1. match(request, options) (2)5.5.3. open(cacheName) (2)6.4. Cross-Origin Resources and CORS (2) (3) object represents a request to response map. Multiple separate objects implementing the Cache interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

    +

    Cache objects are always enumerable via self.caches in insertion order (per ECMAScript 6 Map objects).

    +
    +

    5.4.1. match(request, options)

    +

    match(request, options)#cache-match-methodReferenced in:5.4. Cache5.4.1. match(request, options)5.5.1. match(request, options) (2) (3) (4) method must run these steps or their equivalent:

      -
    1. Let promise be a new promise.
    2. -
    3. Run these steps in parallel: +
    4. Let promise be a new promise. +
    5. + Run these substeps in parallel: +
        +
      1. Let p be the result of running the algorithm specified in matchAll(request, options) method with request and options as the arguments. +
      2. Wait until p settles. +
      3. + If p rejects with an exception, then:
          -
        1. Let responseArray be an empty array.
        2. -
        3. If the optional argument request is omitted, then: -
            -
          1. For each fetching record entry of its request to response map, in key insertion order: -
              -
            1. Add entry.[[value]] to responseArray.
            2. -
            -
          2. -
          3. Resolve promise with responseArray.
          4. -
          5. Abort these steps.
          6. -
          -
        4. -
        5. Else: -
            -
          1. Let r be null.
          2. -
          3. If request is a USVString, then: -
              -
            1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
            2. -
            -
          4. -
          5. Else: -
              -
            1. Set r to request's associated request.
            2. -
            -
          6. -
          7. Set r's url's fragment to null.
          8. -
          9. Let entries be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments.
          10. -
          11. For each entry of entries: -
              -
            1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, add incumbentRecord.[[value]] to responseArray.
            2. -
            3. Else, add entry[1] to responseArray.
            4. -
            -
          12. -
          13. Resolve promise with responseArray.
          14. -
          -
        6. +
        7. Reject promise with that exception.
        -
      4. -
      5. Return promise.
      6. -
      - - - - -

      add(request)

      - -

      add(request) method must run these steps or their equivalent:

      - - -
        -
      1. Let requests be an array containing only request.
      2. -
      3. Set responseArrayPromise to the result of running the algorithm specified in addAll(requests) passing requests as the argument.
      4. -
      5. Let p be transforming responseArrayPromise with onFulfilled.
      6. -
      7. Upon fulfillment of p with value responseArray, perform the following substeps, onFulfilled, in parallel: +
      8. + Else if p resolves with an array, responseArray, then:
          -
        1. Resolve p with undefined.
        2. +
        3. + If responseArray is an empty array, then: +
            +
          1. Resolve promise with undefined. +
          +
        4. + Else: +
            +
          1. Resolve promise with the first element of responseArray. +
        -
      9. -
      10. Return p.
      11. +
      +
    6. Return promise.
    - - - - -

    addAll(requests)

    - -

    addAll(requests) method must run these steps or their equivalent:

    - - +
    +
    +

    5.4.2. matchAll(request, options)

    +

    matchAll(request, options)#cache-matchall-methodReferenced in:5.4. Cache5.4.1. match(request, options)5.4.2. matchAll(request, options) method must run these steps or their equivalent:

      -
    1. Let responsePromiseArray be an empty array.
    2. -
    3. Let requestArray be an empty array.
    4. -
    5. For each request in requests: +
    6. Let promise be a new promise. +
    7. + Run these substeps in parallel: +
        +
      1. Let responseArray be an empty array. +
      2. + If the optional argument request is omitted, then:
          -
        1. Let r be null.
        2. -
        3. If request is a USVString, then: -
            -
          1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
          2. -
          -
        4. -
        5. Else: -
            -
          1. If request's body is non-null, then: -
              -
            1. If request's used flag is set, return a promise rejected with a TypeError.
            2. -
            3. Set request's used flag.
            4. -
            -
          2. -
          3. Set r to request's associated request.
          4. -
          -
        6. -
        7. Set r's url's fragment to null.
        8. -
        9. Add a Request object that represents r to requestArray.
        10. -
        11. If r's url's scheme is not one of "http" and "https", then: -
            -
          1. Add a promise rejected with a "NetworkError" exception to responsePromiseArray.
          2. -
          3. Continue to the next iteration of the loop.
          4. -
          -
        12. -
        13. Let responsePromise be a new promise.
        14. -
        15. Run the following in parallel: -
            -
          • Fetch r.
          • -
          • To process response for response, run these substeps: -
              -
            1. If response's type is error, reject responsePromise with a TypeError.
            2. -
            3. Else, resolve responsePromise with new Response object associated with response.
            4. -
            -
          • -

            This step ensures that the promise for this fetch resolves as soon as the response's headers become available.

            -
          • To process response body for response, do nothing.
          • -
          • To process response end-of-file for response, do nothing.
          • -
          -
        16. -
        17. Add responsePromise to responsePromiseArray.
        18. +
        19. + For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add a copy of entry.[[value]] to responseArray. +
          +
        20. Resolve promise with responseArray. +
        21. Abort these steps.
        -
      3. -
      4. Let p be waiting for all of responsePromiseArray.
      5. -
      6. Let q be transforming p with onFulfilled.
      7. -
      8. Upon fulfillment of p with value responseArray, perform the following substeps, onFulfilled, in parallel: +
      9. + Else:
          -
        1. Let operations be an empty array.
        2. -
        3. For each response in responseArray with the index index: -
            -
          1. If response's body is non-null, then: -
              -
            1. If response's used flag is set, reject q with a TypeError.
            2. -
            3. Set response's used flag.
            4. -
            -
          2. -
          3. Let o be an empty object representing a CacheBatchOperation dictionary.
          4. -
          5. Set the type dictionary member of o to "put".
          6. -
          7. Set the request dictionary member of o to requestArray[index].
          8. -
          9. Set the response dictionary member of o to response.
          10. -
          11. Add o to operations.
          12. -
          -
        4. -
        5. Let resultPromise to the result of running Batch Cache Operations algorithm passing operations as the argument.
        6. -
        7. Upon fulfillment of resultPromise with value responses, perform the following substeps, onFulfilled, in parallel: +
        8. Let r be null. +
        9. + If request is a Request object, then: +
            +
          1. Set r to request’s request. +
          2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array. +
          +
        10. + Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
          +
        11. Set r’s url’s fragment to null. +
        12. Let entries be the result of running Query Cache algorithm passing a Request object associated with r and options as the arguments. +
        13. + For each entry of entries: +
            +
          1. Let response be null. +
          2. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, set response to a copy of incumbentRecord.[[value]]. +
          3. Else, set response to a copy of entry[1]. +
          4. + If r’s method is `HEAD` and options.ignoreMethod is false, then:
              -
            1. For each response in responses: -
                -
              1. Let responseBodyPromise be a new promise.
              2. -
              3. Run the following substeps in parallel: -
                  -
                1. Wait for either end-of-file to have been pushed to response's associated response r's body or for r to have a termination reason.
                2. -
                3. If r had a termination reason, then: -
                    -
                  1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: -
                      -
                    1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
                    2. -
                    -
                  2. -
                  3. Else: -
                      -
                    1. Delete fetchingRecord from request to response map.
                    2. -
                    -
                  4. -
                  5. Reject responseBodyPromise with a TypeError.
                  6. -
                  -
                4. -
                5. Else: -
                    -
                  1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
                  2. -
                  3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
                  4. -
                  5. For each invalidRecord in invalidRecords: -
                      -
                    1. If invalidRecord is not fetchingRecord, delete it from request to response map.
                    2. -
                    -
                  6. -
                  7. Resolve responseBodyPromise with response.
                  8. -
                  -
                6. -
                -
              4. -
              5. Add responseBodyPromise to responseBodyPromiseArray.
              6. -
              -
            2. -
            3. Upon fulfillment of waiting for all of responseBodyPromiseArray, resolve q with undefined.
            4. +
            5. Let actualResponse be response’s associated response, if response’s associated response is not a filtered response, and to response’s associated response’s internal response otherwise. +
            6. Set actualResponse’s body to null.
            -
          5. +
          6. Add response to responseArray. +
          +
        14. Resolve promise with responseArray.
        -
      10. -
      11. Return q.
      12. +
      +
    8. Return promise.
    - - - - -

    put(request, response)

    - -

    put(request, response) method must run these steps or their equivalent:

    - - +
    +
    +

    5.4.3. add(request)

    +

    add(request)#cache-add-methodReferenced in:5.4. Cache5.4.3. add(request) method must run these steps or their equivalent:

      -
    1. Let r be null.
    2. -
    3. If request is a USVString, then: +
    4. Let requests be an array containing only request. +
    5. Set responseArrayPromise to the result of running the algorithm specified in addAll(requests) passing requests as the argument. +
    6. Return the result of transforming responseArrayPromise with a fulfillment handler that returns undefined. +
    +
    +
    +

    5.4.4. addAll(requests)

    +

    addAll(requests)#cache-addAll-methodReferenced in:5.4. Cache5.4.3. add(request)5.4.4. addAll(requests) method must run these steps or their equivalent:

    +
      +
    1. Let responsePromiseArray be an empty array. +
    2. Let requestArray be an empty array. +
    3. + For each request whose type is Request in requests: +
        +
      1. Let r be request’s request. +
      2. If r’s url’s scheme is not one of "http" and "https", or r’s method is not `GET`, return a promise rejected with a TypeError. +
      +
    4. + For each request in requests: +
        +
      1. Let r be the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      2. + If r’s url’s scheme is not one of "http" and "https", then:
          -
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        3. Terminate all the ongoing fetches initiated by requests with reason fatal. +
        4. Break the loop.
        -
      3. -
      4. Else: -
          -
        1. If request's body is non-null, then: +
        2. Set r’s url’s fragment to null. +
        3. Set r’s initiator to "fetch" and destination to "subresource". +
        4. Add a Request object associated with r to requestArray. +
        5. Let responsePromise be a new promise. +
        6. + Run the following substeps in parallel: +
            +
          • Fetch r. +
          • + To process response for response, run these substeps: +
              +
            1. If response’s type is error, or response’s status is not an ok status, reject responsePromise with a TypeError. +
            2. + Else if response’s header list contains a header named `Vary`, then:
                -
              1. If request's used flag is set, return a promise rejected with a TypeError.
              2. -
              3. Set request's used flag.
              4. +
              5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
              6. Let matchAsterisk be false. +
              7. + For each f in varyHeaders: +
                  +
                1. If f matches "*", set matchAsterisk to true and break the loop. +
                +
              8. If matchAsterisk is true, reject responsePromise with a TypeError. +
              9. Else, resolve responsePromise with a new Response object associated with response and a new Headers object whose guard is "immutable".
              -
            3. -
            4. Set r to request's associated request.
            5. -
            -
          • -
          • Set r's url's fragment to null.
          • -
          • If response's body is non-null, then: +
          • Else, resolve responsePromise with a new Response object associated with response and a new Headers object whose guard is "immutable". +
        +

        This step ensures that the promise for this fetch resolves as soon as the response’s headers become available.

        +
      5. To process response body for response, do nothing. +
      6. To process response end-of-file for response, do nothing. + +
      7. Add responsePromise to responsePromiseArray. +
      +
    5. Let p be waiting for all of responsePromiseArray. +
    6. + Return the result of transforming p with a fulfillment handler that, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. Let operations be an empty array. +
      2. + For each response in responseArray with the index index:
          -
        1. If response's used flag is set, return a promise rejected with a TypeError.
        2. -
        3. Set response's used flag.
        4. +
        5. Let o be an empty object representing a CacheBatchOperation dictionary. +
        6. Set the type dictionary member of o to "put". +
        7. Set the request dictionary member of o to requestArray[index]. +
        8. Set the response dictionary member of o to response. +
        9. Add o to operations.
        -
      3. -
      4. Let operations be an empty array.
      5. -
      6. Let o be an empty object representing a CacheBatchOperation dictionary.
      7. -
      8. Set the type dictionary member of o to "put".
      9. -
      10. Set the request dictionary member of o to a Request object that represents r.
      11. -
      12. Set the response dictionary member of o to response.
      13. -
      14. Add o to operations.
      15. -
      16. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
      17. -
      18. Let p be transforming resultPromise with onFulfilled.
      19. -
      20. Upon fulfillment of resultPromise with value responses, perform the following substeps, onFulfilled, in parallel: +
      21. Let resultPromise be the result of running Batch Cache Operations algorithm passing operations as the argument. +
      22. + Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel:
          -
        1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r's body or for r to have a termination reason.
        2. -
        3. If r had a termination reason, then: +
        4. Let responseBodyPromiseArray be an empty array. +
        5. + For each response in responses: +
            +
          1. Let responseBodyPromise be a new promise. +
          2. + Run the following substeps in parallel:
              -
            1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
            2. Wait for either end-of-file to have been pushed to response’s associated response r’s body or for r to have a termination reason. +
            3. + If r had a termination reason, then: +
                +
              1. + If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then:
                  -
                1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
                2. +
                3. Set fetchingRecord in request to response map to the copy of incumbentRecord.
                -
              2. -
              3. Else: +
              4. + Else:
                  -
                1. Delete fetchingRecord from request to response map.
                2. +
                3. Delete fetchingRecord from request to response map.
                -
              5. -
              6. Reject p with a TypeError.
              7. -
              -
            4. -
            5. Else: -
                -
              1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
              2. -
              3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument.
              4. -
              5. For each invalidRecord in invalidRecords: +
              6. Reject responseBodyPromise with a TypeError. +
              +
            6. + Else: +
                +
              1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord. +
              2. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument. +
              3. + For each invalidRecord in invalidRecords:
                  -
                1. If invalidRecord is not fetchingRecord, delete it from request to response map.
                2. +
                3. If invalidRecord is not fetchingRecord, delete it from request to response map.
                -
              4. -
              5. Resolve p with undefined.
              6. +
              7. Resolve responseBodyPromise with response. +
            -
          3. +
          4. Add responseBodyPromise to responseBodyPromiseArray. +
          +
        6. Let q be waiting for all of responseBodyPromiseArray. +
        7. Return the result of transforming q with a fulfillment handler that returns undefined.
        -
      23. -
      24. Return p.
      25. +
    - - - - -

    delete(request, options)

    - -

    delete(request, options) method must run these steps or their equivalent:

    - - +
    +
    +

    5.4.5. put(request, response)

    +

    put(request, response)#cache-put-methodReferenced in:5.4. Cache5.4.5. put(request, response) method must run these steps or their equivalent:

      -
    1. Let r be null.
    2. -
    3. If request is a USVString, then: +
    4. Let r be null. +
    5. + If request is a Request object, then: +
        +
      1. Set r to request’s request. +
      2. If r’s url’s scheme is not one of "http" and "https", or r’s method is not `GET`, return a promise rejected with a TypeError. +
      +
    6. + Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      2. If r’s url’s scheme is not one of "http" and "https", return a promise rejected with a TypeError. +
      +
    7. Set r’s url’s fragment to null. +
    8. + If response’s associated response’s header list contains a header named `Vary`, then: +
        +
      1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
      2. + For each f in varyHeaders:
          -
        1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
        2. +
        3. If f matches "*", return a promise rejected with a TypeError.
        -
      3. -
      4. Else: +
      +
    9. If response is disturbed or locked, return a promise rejected with a TypeError. +
    10. Let newResponse be a new Response object associated with response’s associated response and a new Headers object whose guard is response’s Headers' guard. +
    11. + If response’s body is non-null, run these substeps: +
        +
      1. Let dummyStream be an empty ReadableStream object. +
      2. Set response’s body to a new body whose stream is dummyStream. +
      3. Let reader be the result of getting a reader from dummyStream. +
      4. Read all bytes from dummyStream with reader. +
      +
    12. Let operations be an empty array. +
    13. Let o be an empty object representing a CacheBatchOperation dictionary. +
    14. Set the type dictionary member of o to "put". +
    15. Set the request dictionary member of o to a Request object associated with r. +
    16. Set the response dictionary member of o to newResponse. +
    17. Add o to operations. +
    18. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument. +
    19. + Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
        +
      1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r’s body or for r to have a termination reason. +
      2. + If r had a termination reason, then:
          -
        1. Set r to request's associated request.
        2. +
        3. + If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
            +
          1. Set fetchingRecord in request to response map to the copy of incumbentRecord. +
          +
        4. + Else: +
            +
          1. Delete fetchingRecord from request to response map. +
          +
        5. Throw a TypeError.
        -
      3. -
      4. Set r's url's fragment to null.
      5. -
      6. Let operations be an empty array.
      7. -
      8. Let o be an empty object representing a CacheBatchOperation dictionary.
      9. -
      10. Set the type dictionary member of o to "delete".
      11. -
      12. Set the request dictionary member of o to a Request object that represents r.
      13. -
      14. Set the options dictionary member of o to options.
      15. -
      16. Add o to operations.
      17. -
      18. Let resultPromise to the result of running Batch Cache Operations passing operations as the argument.
      19. -
      20. Let p be transforming resultPromise with onFulfilled.
      21. -
      22. Upon fulfillment of p with responseArray, perform the following substeps, onFulfilled, in parallel: +
      23. + Else:
          -
        1. If responseArray is not null, then: -
            -
          1. Resolve p with true.
          2. -
          -
        2. -
        3. Else: -
            -
          1. Resolve p with false.
          2. -
          -
        4. +
        5. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord. +
        6. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument. +
        7. + For each invalidRecord in invalidRecords: +
            +
          1. If invalidRecord is not fetchingRecord, delete it from request to response map. +
          +
        8. Return undefined.
        -
      24. -
      25. Return p.
      26. +
    - - - - -

    keys(request, options)

    - -

    keys(request, options) method must run these steps or their equivalent:

    - - +
    +
    +

    5.4.6. delete(request, options)

    +

    delete(request, options)#cache-delete-methodReferenced in:5.4. Cache5.4.6. delete(request, options) method must run these steps or their equivalent:

      -
    1. Let promise be a new promise.
    2. -
    3. Run these steps in parallel: +
    4. Let r be null. +
    5. + If request is a Request object, then: +
        +
      1. Set r to request’s request. +
      2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, return a promise resolved with false. +
      +
    6. + Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      +
    7. Set r’s url’s fragment to null. +
    8. Let operations be an empty array. +
    9. Let o be an empty object representing a CacheBatchOperation dictionary. +
    10. Set the type dictionary member of o to "delete". +
    11. Set the request dictionary member of o to a Request object associated with r. +
    12. Set the options dictionary member of o to options. +
    13. Add o to operations. +
    14. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument. +
    15. + Return the result of transforming resultPromise with a fulfillment handler, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. If responseArray is not null, return true. +
      2. Else, return false. +
      +
    +
    +
    +

    5.4.7. keys(request, options)

    +

    keys(request, options)#cache-keys-methodReferenced in:5.4. Cache5.4.7. keys(request, options) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let resultArray be an empty array. +
      2. + If the optional argument request is omitted, then:
          -
        1. Let resultArray be an empty array.
        2. -
        3. If the optional argument request is omitted, then: -
            -
          1. For each fetching record entry of its request to response map, in key insertion order: -
              -
            1. Add entry.[[key]] to resultArray.
            2. -
            -
          2. -
          -
        4. -
        5. Else: -
            -
          1. Let r be null.
          2. -
          3. If request is a USVString, then: -
              -
            1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
            2. -
            -
          4. -
          5. Else: -
              -
            1. Set r to request's associated request.
            2. -
            -
          6. -
          7. Set r's url's fragment to null.
          8. -
          9. Let requestResponseArray be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments.
          10. -
          11. For each requestResponse in requestResponseArray: -
              -
            1. Add requestResponse[0] to resultArray.
            2. -
            -
          12. -
          -
        6. -
        7. Resolve promise with resultArray.
        8. +
        9. + For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add entry.[[key]] to resultArray. +
        -
      3. -
      4. Return promise.
      5. -
      - - - - - -

      CacheStorage

      - -[Exposed=(Window,Worker)] -interface CacheStorage { -Promise<Response> match(RequestInfo request, optional CacheQueryOptions options); -Promise<boolean> has(DOMString cacheName); -Promise<Cache> open(DOMString cacheName); -Promise<boolean> delete(DOMString cacheName); -Promise<sequence<DOMString>> keys(); -}; - - -

      CacheStorage interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

      - -

      A CacheStorage object represents a name to cache map. Multiple separate objects implementing the CacheStorage interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

      - - -

      match(request, options)

      - -

      match(request, options) method must run these steps or their equivalent:

      - - -
        -
      1. Let cacheName be null.
      2. -
      3. If the optional argument options is not omitted, then: +
      4. + Else:
          -
        1. Set cacheName to options.cacheName.
        2. +
        3. Let r be null. +
        4. + If request is a Request object, then: +
            +
          1. Set r to request’s request. +
          2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array. +
          +
        5. + Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
          +
        6. Set r’s url’s fragment to null. +
        7. Let requestResponseArray be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments. +
        8. + For each requestResponse in requestResponseArray: +
            +
          1. Add requestResponse[0] to resultArray. +
        -
      5. -
      6. If cacheName is not null, then: +
      7. Resolve promise with resultArray. +
      +
    3. Return promise. +
    +
    +
    +
    +

    5.5. CacheStorage

    +
    [Exposed=(Window,Worker)]
    +interface CacheStorage {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<boolean> has(DOMString cacheName);
    +  [NewObject] Promise<Cache> open(DOMString cacheName);
    +  [NewObject] Promise<boolean> delete(DOMString cacheName);
    +  [NewObject] Promise<sequence<DOMString>> keys();
    +};
    +
    +

    CacheStorage interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

    +

    The user agent must create a CacheStorage object when a Window object or a WorkerGlobalScope object is created and associate it with that object.

    +

    A CacheStorage#cache-storage-interfaceReferenced in:5.3. self.caches (2)5.3.1. caches5.5. CacheStorage (2) (3) (4) (5) object represents a name to cache map of its associated global object’s environment settings object’s origin. Multiple separate objects implementing the CacheStorage interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

    +
    +

    5.5.1. match(request, options)

    +

    match(request, options)#cache-storage-match-methodReferenced in:5.5. CacheStorage5.5.1. match(request, options) method must run these steps or their equivalent:

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. + If options.cacheName is present, then: +
        +
      1. + Return a new promise p and run the following substeps in parallel:
          -
        1. Return a promise, p, resolved with the result of running the following substeps: +
        2. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
            +
          1. + If options.cacheName matches entry.[[key]], then:
              -
            1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: -
                -
              1. If cacheName matches entry.[[key]], then: -
                  -
                1. Resolve p with the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).)
                2. -
                3. Abort these steps.
                4. -
                -
              2. -
              -
            2. -
            3. Reject p with an "NotFoundError" exception.
            4. +
            5. Resolve p with the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).) +
            6. Abort these steps.
            -
          2. +
          +
        3. Reject p with a "NotFoundError" exception.
        -
      2. -
      3. Else: +
      +
    3. + Else: +
        +
      1. Let p be a promise resolved with undefined. +
      2. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order:
          -
        1. Set p to transforming the result of running the algorithm specified in keys() method, with onFulfilled.
        2. -
        3. Upon fulfillment of p with value keys, perform the following substeps, onFulfilled, in parallel: -
            -
          1. For each key in keys: -
              -
            1. Let q be the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing key as thisArgument to the [[Call]] internal method of match(request, options).)
            2. -
            3. Upon fulfillment of q with value matchedResponse: -
                -
              1. If matchedResponse is not undefined, then: -
                  -
                1. Resolve p with matchedResponse.
                2. -
                3. Abort these steps.
                4. -
                -
              2. -
              -
            4. -
            5. Upon rejection of q with value err: -
                -
              1. Reject p with err.
              2. -
              3. Abort these steps.
              4. -
              -
            6. -
            -
          2. -
          3. Resolve p with undefined.
          4. -
          -
        4. -
        5. Return p.
        6. +
        7. + Set p to the result of transforming itself with a fulfillment handler that, when called with argument v, performs the following substeps in parallel: +
            +
          1. If v is not undefined, return v. +
          2. Return the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).) +
        -
      3. +
      4. Return p. +
    - - - - -

    has(cacheName)

    - -

    has(cacheName) method must run these steps or their equivalent:

    - - +
    +
    +

    5.5.2. has(cacheName)

    +

    has(cacheName)#cache-storage-has-methodReferenced in:5.5. CacheStorage5.5.2. has(cacheName)5.5.4. delete(cacheName) method must run these steps or their equivalent:

      -
    1. Return a promise, p, resolved with the result of running the following substeps: +
    2. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    3. + Return a promise p resolved with the result of running the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order:
          -
        1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: -
            -
          1. If cacheName matches entry.[[key]], then: -
              -
            1. Return true.
            2. -
            -
          2. -
          -
        2. -
        3. Return false.
        4. +
        5. + If cacheName matches entry.[[key]], then: +
            +
          1. Return true. +
        -
      2. +
      3. Return false. +
    - - - - -

    open(cacheName)

    - -

    open(cacheName) method must run these steps or their equivalent:

    - - +
    +
    +

    5.5.3. open(cacheName)

    +

    open(cacheName)#cache-storage-open-methodReferenced in:5.5. CacheStorage5.5.3. open(cacheName) method must run these steps or their equivalent:

      -
    1. Return a promise, p, resolved with the result of running the following substeps: +
    2. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    3. Let p be a new promise. +
    4. + Run the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order:
          -
        1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: -
            -
          1. If cacheName matches entry.[[key]], then: -
              -
            1. Return a new Cache object which is a copy of entry.[[value]].
            2. -
            3. Abort these steps.
            4. -
            -
          2. -
          -
        2. -
        3. Let cache be a new Cache object.
        4. -
        5. Set a newly-created Record {[[key]]: cacheName, [[value]]: cache} to name to cache map.
        6. -
        7. Return cache.
        8. +
        9. + If cacheName matches entry.[[key]], then: +
            +
          1. Resolve p with a new Cache object which is a copy of entry.[[value]]. +
          2. Abort these steps. +
        -
      2. +
      3. Let cache be a new Cache object. +
      4. Set a newly-created Record {[[key]]: cacheName, [[value]]: cache} to name to cache map. If this cache write operation failed due to exceeding the granted quota limit, reject p with a "QuotaExceededError" exception and abort these steps. +
      5. Resolve p with cache. +
      +
    5. Return p.
    - - - - -

    delete(cacheName)

    - -

    delete(cacheName) method must run these steps or their equivalent:

    - - +
    +
    +

    5.5.4. delete(cacheName)

    +

    delete(cacheName)#cache-storage-delete-methodReferenced in:5.5. CacheStorage5.5.4. delete(cacheName) method must run these steps or their equivalent:

      -
    1. Let p be the result of running the algorithm specified in has(cacheName) method with cacheName as the argument.
    2. -
    3. Let q be transforming p with onFulfilled.
    4. -
    5. Upon fulfillment of p with value cacheExists, perform the following substeps, onFulfilled, in parallel: +
    6. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    7. Let p be the result of running the algorithm specified in has(cacheName) method with cacheName as the argument. +
    8. + Return the result of transforming p with a fulfillment handler that, when called with argument cacheExists, performs the following substeps in parallel: +
        +
      1. + If cacheExists is true, then:
          -
        1. If cacheExists is true, then: -
            -
          1. Delete a Record {[[key]], [[value]]} entry of its name to cache map where cacheName matches entry.[[key]].
          2. -
          3. Resolve q with true.
          4. -
          5. Abort these steps.
          6. -
          -
        2. -
        3. Else: -
            -
          1. Resolve q with flase.
          2. -
          -
        4. +
        5. Delete a Record {[[key]], [[value]]} entry from its name to cache map where cacheName matches entry.[[key]]. +
        6. Return true. +
        7. Abort these steps. +
        +

        After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.

        +
      2. + Else: +
          +
        1. Return false.
        -
      3. -
      4. Return q.
      5. +
    - - - - -

    keys()

    - -

    keys() method must run these steps or their equivalent:

    - -

    The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

    - - +
    +
    +

    5.5.5. keys()

    +

    keys()#cache-storage-keys-methodReferenced in:5.5. CacheStorage5.5.5. keys() method must run these steps or their equivalent:

    +

    The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

      -
    1. Let resultArray be an empty array.
    2. -
    3. Return a promise, p, resolved with the result of running the following substeps: +
    4. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    5. Let resultArray be an empty array. +
    6. + Return a promise p resolved with the result of running the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order:
          -
        1. For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: -
            -
          1. Add entry.[[key]] to resultArray.
          2. -
          -
        2. -
        3. Return resultArray.
        4. +
        5. Add entry.[[key]] to resultArray.
        -
      2. -
      - - - - - - -

      Security Considerations

      - -

      Service workers should be implemented to be HTTPS-only. The reasons for SSL-only support include:

      -
        -
      • Better to protect end users from man-in-the-middle attacks
      • -
      • Do good by encouraging HTTPS adoption
      • -
      • Existing "playground" services (e.g. github.io) now work with HTTPS
      • -
      • HTTPS is coming across much more of the web quickly
      • -
      • Devtools can loosen the restriction for development (file://, localhost, etc.)
      • -
      - -

      The section will be updated.

      - - -

      Origin Relativity

      - -

      One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

      -

      The section will be updated.

      -
      - - -

      Cross-Origin Resources & CORS

      - -

      Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to XHR many sorts of off-origin resources when appropriate CORS headers are set.

      -

      ServiceWorkers enable this by allowing Caches to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the Cache as Response objects with the type attribute set to "basic", the objects stored are Response objects with the type attribute set to "opaque". Responses typed "opaque" provide a much less expressive API than Responses typed "basic"; the bodies and headers cannot be read or set, nor many of the other aspects of their content inspected. They can be passed to event.respondWith(r) method and event.forwardTo(url) method in the same manner as the Responses typed "basic", but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Caches to store them allows applications to avoid re-architecting in most cases.

      -

      The section will be updated.

      -
      -
      - - -

      Storage Considerations

      - -

      Service workers should take a dependency on Quota Management in preparation for an extension event that communicates storage pressure and pre-eviction information to the application.

      -

      The section will be updated.

      -
      - - -

      Extensibility

      - -

      Service workers are extensible from other specifications.

      - - -

      Define API bound to Service Worker Registration

      -

      Specifications may define an API tied to a service worker registration by using partial interface definition to the ServiceWorkerRegistration interface where it may define the specification specific attributes and methods:

      - - partial interface ServiceWorkerRegistration { +
    7. Return resultArray. +
    + +
    +
    +
    +
    +

    6. Security Considerations

    +
    +

    6.1. Secure Context

    +

    Service workers must execute in secure contexts. Service worker clients must also be secure contexts to register a service worker registration, to get access to the service worker registrations and the service workers, to do messaging with the service workers, and to be manipulated by the service workers. This effectively means that service workers and their service worker clients should be hosted over HTTPS. A user agent may allow localhost, 127.0.0.0/8, and ::1/128 for development purpose. (Note that they may still be secure contexts.) The primary reason for this restriction is to protect users from the risks associated with insecure contexts.

    +
    +
    +

    6.2. Content Security Policy

    +

    Whenever a user agent invokes Run Service Worker algorithm with a service worker serviceWorker:

    +
      +
    • If serviceWorker’s script resource was delivered with a Content-Security-Policy HTTP header containing the value policy, the user agent must enforce policy for serviceWorker. +
    • If serviceWorker’s script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value policy, the user agent must monitor policy for serviceWorker. +
    +

    +

    The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).

    +
    +
    +

    6.3. Origin Relativity

    +
    +

    6.3.1. Origin restriction

    +

    This section is non-normative.

    +

    A Service worker executes in the registering service worker client’s origin. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

    +
    +
    +

    6.3.2. importScripts(urls)

    +

    When the importScripts(urls)#importscripts-methodReferenced in:6.3.1. Origin restriction method is called on a ServiceWorkerGlobalScope object, the user agent must import scripts into worker global scope, with the following options:

    +

    To validate the state, the user agent must do nothing.

    +

    To get a fetch result, the user agent must run the following steps:

    +
      +
    1. Let serviceWorker be the settings object’s global object’s service worker. +
    2. + If serviceWorker’s imported scripts updated flag is unset, then: +
        +
      1. Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set. +
      +
    3. + Else: +
        +
      1. If there exists a corresponding Record record for url in serviceWorker’s script resource map, set the script resource to record.[[value]]. +
      2. Else, set the script resource to null. +
      +
    +

    To postprocess the fetch result, the user agent must run the following steps:

    +
      +
    1. + If serviceWorker’s imported scripts updated flag is unset, then: +
        +
      1. If the fetching attempt failed (e.g. the server returned a 4xx or 5xx status code or equivalent, or there was a DNS error), throw a "NetworkError" exception and abort all these steps. +
      2. + Else: +
          +
        1. If there exists a corresponding Record record for the resulting absolute URL url in serviceWorker’s script resource map, set record.[[value]] to the fetched script resource. +
        2. Else, set a newly-created Record {[[key]]: url, [[value]]: the fetched script resource} to serviceWorker’s script resource map. +
        +
      +
    2. Else, if the script resource is null, throw a "NetworkError" exception and abort all these steps. +
    +
    +
    +
    +

    6.4. Cross-Origin Resources and CORS

    +

    This section is non-normative.

    +

    Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to fetch many sorts of off-origin resources when appropriate CORS headers are set.

    +

    Service workers enable this by allowing Caches to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the Cache as Response objects whose corresponding responses are basic filtered response, the objects stored are Response objects whose corresponding responses are either CORS filtered responses or opaque filtered responses. They can be passed to event.respondWith(r) method in the same manner as the Response objects whose corresponding responses are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Caches to store them allows applications to avoid re-architecting in most cases.

    +
    +
    +

    6.5. Implementer Concerns

    +

    This section is non-normative.

    +

    The implementers are encouraged to note:

    +
      +
    • Plug-ins should not load via service workers. As plug-ins may get their security origins from their own urls, the embedding service worker cannot handle it. For this reason, the Handle Fetch algorithm makes the potential-navigation-or-subresource request (whose context is either <embed> or <object>) immediately fallback to the network without dispatching fetch event. +
    • Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with service workers. +
    +

    +
    +
    +

    6.6. Privacy

    +

    Service workers introduce new persistent storage features including scope to registration map (for service worker registrations and their service workers), request to response map and name to cache map (for caches), and script resource map (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages should be cleared when users intend to clear them and should maintain and interoperate with existing user controls e.g. purging all existing persistent storages.

    +
    +
    +
    +

    7. Storage Considerations

    +

    Service workers should take a dependency on Quota Management API that extends the ServiceWorkerGlobalScope with the event listeners onbeforeevicted and onevicted to detect a storage pressure and give pre-eviction information to the application.

    +

    The cache write operations in service workers when failed due to exceeding the granted quota limit should throw "QuotaExceededError" exception.

    +
    +

    8. Extensibility

    +

    Service workers are extensible from other specifications.

    +
    +

    8.1. Define API bound to Service Worker Registration

    +

    Specifications may define an API tied to a service worker registration by using partial interface definition to the ServiceWorkerRegistration interface where it may define the specification specific attributes and methods:

    +
    partial interface ServiceWorkerRegistration {
       // e.g. define an API namespace
       readonly attribute APISpaceType APISpace;
       // e.g. define a method
    -  Promise<T> methodName(list of arguments);
    +  Promise<T> methodName(list of arguments);
     };
    -
    -  
    -
    -  
    -    

    Define Functional Event

    -

    Specifications may define a functional event by extending ExtendableEvent interface:

    - - // e.g. define FunctionalEvent interface +
    +
    +
    +

    8.2. Define Functional Event

    +

    Specifications may define a functional event by extending ExtendableEvent interface:

    +
    // e.g. define FunctionalEvent interface
     interface FunctionalEvent : ExtendableEvent {
    -  // add a functional event's own attributes and methods
    +  // add a functional event’s own attributes and methods
     };
    -
    -  
    -
    -  
    -    

    Define Event Handler

    -

    Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the ServiceWorkerGlobalScope interface:

    - - partial interface ServiceWorkerGlobalScope { +
    +
    +
    +

    8.3. Define Event Handler

    +

    Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the ServiceWorkerGlobalScope interface:

    +
    partial interface ServiceWorkerGlobalScope {
       attribute EventHandler onfunctionalevent;
    -};
    -  
    -
    -  
    -    

    Request Functional Event Dispatch

    -

    To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm with its service worker registration registration and the algorithm callbackSteps as the arguments.

    - -

    Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a ServiceWorkerGlobalScope object) at which it may fire its functional events. This algorithm is called on a task run by Handle Functional Event On Scheduled Task algorithm which is queued by Handle Functional Event algorithm.

    - -

    See an example hook defined in Notifications API.

    -
    - - - -

    Appendix A: Algorithms

    - -

    The following definitions are the user agent's internal data structures used throughout the specification.

    - -

    A scope to registration map is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a scope url and [[value]] is a service worker registration.

    - -

    An algorithm thread queue is a thread safe queue used to synchronize the set of concurrent entries of algorithm steps. The queue contains timestamps (with the assumptions), gained by algorithms, as its elements. The queue should satisfy the general properties of FIFO queue.

    - -

    A registration queue is an algorithm thread queue for synchronizing the set of concurrent registration requests. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

    - -

    An installation queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

    - -

    An installation result handle queue is an algorithm thread queue for synchronizing the set of concurrent installation jobs. The user agent must maintain a separate queue for each service worker registration keyed by its scope url. The queue is initially empty.

    - - -

    Register

    - - -
    -
    Input
    -
    client, a service worker client
    -
    scriptURL, an absolute URL
    -
    scopeURL, an absolute URL
    -
    Output
    -
    promise, a promise
    -
    -
      -
    1. If the result of running Is origin potentially trustworthy with the origin of scriptURL as the argument is Not Trusted, then: +}; +
    +
    +
    +

    8.4. Request Functional Event Dispatch

    +

    To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

    +

    Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a ServiceWorkerGlobalScope object) at which it may fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm.

    +

    See an example hook defined in Notifications API.

    +
    +
    +
    +

    Appendix A: Algorithms

    +

    The following definitions are the user agent’s internal data structures used throughout the specification.

    +

    A scope to registration map#dfn-scope-to-registration-mapReferenced in:2.2.1. Lifetime2.4. Selection and Use (2)3.4.2. ready3.4.5. getRegistrations()6.6. PrivacyHandle Functional EventHandle User Agent ShutdownSet RegistrationClear RegistrationMatch Service Worker RegistrationGet Registration is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a scope url and [[value]] is a service worker registration.

    +

    A job#dfn-jobReferenced in:Appendix A: Algorithms (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)Create Job (2)Schedule JobFinish JobResolve Job PromiseReject Job PromiseRegisterUpdateInstallUnregister is an abstraction of one of register, update, and unregister request for a service worker registration.

    +

    A job has a job type#dfn-job-typeReferenced in:Appendix A: AlgorithmsCreate Job (2)Run Job (2) (3)Update, which is one of register, update, and unregister.

    +

    A job has a scope url#dfn-job-scope-urlReferenced in:Appendix A: Algorithms (2) (3)Create JobRegister (2) (3)UpdateUnregister (2) (a URL).

    +

    A job has a script url#dfn-job-script-urlReferenced in:Appendix A: AlgorithmsCreate JobRegister (2) (3)Update (2) (3) (4) (5) (6) (7) (a URL).

    +

    A job has a worker type#dfn-job-worker-typeReferenced in:3.2.5. update()3.4.3. register(scriptURL, options)Update (2)Soft Update ("classic" or "module").

    +

    A job has a client#dfn-job-clientReferenced in:Create JobRun JobRegister (2)Update (2)Unregister (a service worker client). It is initially null.

    +

    A job has a promise#dfn-job-promiseReferenced in:Create JobSchedule Job (2)Resolve Job PromiseReject Job PromiseInstall (a promise). It is initially null.

    +

    A job has a list of equivalent job promises#dfn-job-list-of-equivalent-job-promisesReferenced in:Schedule JobResolve Job PromiseReject Job Promise (a list of promises). It is initially the empty list.

    +

    A job has a force bypass cache flag#dfn-job-force-bypass-cache-flagReferenced in:Soft Update It is initially unset.

    +

    Two jobs are equivalent#dfn-job-equivalentReferenced in:Schedule Job when their job type is the same and:

    + +

    +

    A job queue#dfn-job-queueReferenced in:Appendix A: Algorithms (2) (3) (4) (5) (6)Schedule Job (2) (3) (4)Run Job (2)Finish Job (2) (3) (4) is a queue used to synchronize the set of concurrent jobs. The job queue contains jobs as its elements. The job queue should satisfy the general properties of FIFO queue. A user agent must maintain a separate job queue for each service worker registration keyed by its scope url. A job queue is initially empty. Unless stated otherwise, the job queue referenced from the algorithm steps is a job queue for the job’s scope url.

    +
    +

    Create Job

    +
    +
    Input +
    jobType, a job type +
    scopeURL, a URL +
    scriptURL, a URL +
    promise, a promise +
    client, a service worker client +
    Output +
    job, a job +
    +
      +
    1. Let job be a new job. +
    2. Set job’s job type to jobType. +
    3. Set job’s scope url to scopeURL. +
    4. Set job’s script url to scriptURL. +
    5. Set job’s promise to promise. +
    6. Set job’s client to client. +
    7. Return job. +
    +
    +
    +

    Schedule Job

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. + If the job queue is empty, then:
        -
      1. Return a promise rejected with a "SecurityError" exception.
      2. +
      3. Push job to the job queue and invoke Run Job.
      -
    2. -
    3. If the origin of scriptURL is not client's origin, then: +
    4. + Else:
        -
      1. Return a promise rejected with a "SecurityError" exception.
      2. +
      3. Let lastJob be the element at the back of the job queue. +
      4. If job is equivalent to lastJob and lastJob’s promise has not settled, append job’s promise to lastJob’s list of equivalent job promises. +
      5. Else, push job to the job queue.
      -
    5. -
    6. If the origin of scopeURL is not client's origin, then: +
    +
    +
    +

    Run Job

    +
    +
    Input +
    none +
    Output +
    none +
    +
      +
    1. Assert: the job queue is not empty. +
    2. Let job be the element in the front of the job queue. +
    3. If job’s job type is register, invoke Register with job and continue running these steps in parallel. +
    4. + Else if job’s job type is update, invoke Update with job and continue running these steps in parallel. +

      For a register job and an update job, the user agent delays invoking Register and Update respectively until after the document initiated the job has been dispatched DOMContentLoaded event. If the job’s client is a worker client, it is delayed until after the worker script has evaluated.

      +
    5. Else if job’s job type is unregister, invoke Unregister with job and continue running these steps in parallel. +
    +
    +
    +

    Finish Job

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. Assert: the top element in the job queue is job. +
    2. Pop the top element from the job queue. +
    3. If the job queue is not empty, invoke Run Job with the top element of the job queue. +
    +
    +
    +

    Resolve Job Promise

    +
    +
    Input +
    job, a job +
    value, any +
    Output +
    none +
    +
      +
    1. Resolve job’s promise with value. +
    2. + For each promise in job’s list of equivalent job promises:
        -
      1. Return a promise rejected with a "SecurityError" exception.
      2. +
      3. Resolve promise with value.
      -
    3. -
    4. Let scriptPathname be "/" concatenated with the strings, except the last string that denotes the script's file name, in scriptURL's path (including empty strings), separated from each other by "/".
    5. -
    6. Let scopePathname be "/" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/".
    7. -
    8. If scopePathname starts with scriptPathname, do nothing.
    9. -
    10. Else, return a promise rejected with a "SecurityError" exception.
    11. -
    12. Run the following substeps atomically: +
    +
    +
    +

    Reject Job Promise

    +
    +
    Input +
    job, a job +
    reason, an exception +
    Output +
    none +
    +
      +
    1. Reject job’s promise with reason. +
    2. + For each promise in job’s list of equivalent job promises:
        -
      1. Let registration be the result of running the Get Registration algorithm passing scopeURL as the argument.
      2. - -
      3. If registration is not null, then: -
          -
        1. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
        2. -
        3. If newestWorker is not null, scriptURL is equal to newestWorker's script url, and scriptURL is equal to registration's registering script url, then: -
            -
          1. If newestWorker is an active worker, then: -
              -
            1. If registration's uninstalling flag is set, unset it.
            2. -
            3. Return a promise resolved with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
            4. -
            -
          2. -
          -
        4. -
        -
      4. -
      5. Else: -
          -
        1. Set registration to the result of running Set Registration algorithm passing scopeURL as its argument.
        2. -
        -
      6. -
      7. Set registration's registering script url to scriptURL.
      8. -
      9. Return the result of running the Update algorithm, or its equivalent, passing client and registration as the argument.
      10. +
      11. Reject promise with reason.
      -
    3. -
    - - - - -

    Update

    - -

    The algorithm uses registration queue to synchronize the set of multiple registration requests. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

    - - - -
    -
    Input
    -
    client, a service worker client
    -
    registration, a service worker registration
    -
    Output
    -
    promise, a promise
    -
    -
      -
    1. Let p be a new promise.
    2. -
    3. Generate a timestamp and let timeStamp be the result value.
    4. -
    5. Push timeStamp to registration queue, installation queue, and installation result handle queue.
    6. -
    7. Run the following substeps in parallel: +
    +
    +
    +

    Register

    +
    +
    Input +
    job, a job +
    Output +
    promise, a promise +
    +
      +
    1. + If the result of running Is origin potentially trustworthy with the origin of job’s script url as the argument is Not Trusted, then:
        -
      1. CheckPriority: If the value of the top element of registration queue matches timeStamp, then: -
          -
        1. Pop the top element from registration queue.
        2. -
        -
      2. -
      3. Else: -
          -
        1. Wait until the top element of registration queue is popped.
        2. -
        3. Jump to the step labeled CheckProirity.
        4. -
        -

        Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

        -
      4. -
      5. Run the following substeps atomically: +
      6. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      7. Invoke Finish Job with job and abort these steps. +
      +
    2. + If the origin of job’s script url is not job’s client’s origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    3. + If the origin of job’s scope url is not job’s client’s origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    4. Let registration be the result of running the Get Registration algorithm passing job’s scope url as the argument. +
    5. + If registration is not null, then: +
        +
      1. If registration’s uninstalling flag is set, unset it. +
      2. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument. +
      3. + If newestWorker is not null and job’s script url equals newestWorker’s script url, then: +
          +
        1. + If newestWorker is an active worker, then:
            -
          1. If registration's installing worker is not null, then: -
              -
            1. Terminate registration's installing worker.
            2. -
            3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
            4. -
            5. Set registration's installing worker to null.
            6. -
            7. The user agent may abort in-flight requests triggered by registration's installing worker.
            8. -
            -
          2. -
          3. Let r be the associated request of the result of invoking the initial value of Request as constructor with registration's registering script url. If this throws an exception, then: -
              -
            1. Reject p with the exception.
            2. -
            3. Pop the top element from installation queue and installation result handle queue.
            4. -
            5. If the result of running Get Newest Worker algorithm is null, then: -
                -
              1. Invoke Clear Registration algorithm passing registration as its argument.
              2. -
              -
            6. -
            7. Abort these steps.
            8. -
            -
          4. -
          5. Set r's context to serviceworker.
          6. -
          7. Append `Service-Worker`/`script` to r's header list.
          8. -
          9. Set r's skip service worker flag and r's synchronous flag.
          10. -
          11. Let response be the result of running fetch using r, forcing a network fetch if cached entry is greater than 1 day old.
          12. -
          13. If response is a network error, then: -
              -
            1. If r's redirect count is not zero, then: -
                -
              1. Reject p with a "SecurityError" exception.
              2. -
              3. Pop the top element from installation queue and installation result handle queue.
              4. -
              5. If the result of running Get Newest Worker algorithm is null, then: -
                  -
                1. Invoke Clear Registration algorithm passing registration as its argument.
                2. -
                -
              6. -
              7. Abort these steps.
              8. -
              -
            2. -
            3. Else: -
                -
              1. Reject p with a "NetworkError" exception.
              2. -
              3. Pop the top element from installation queue and installation result handle queue.
              4. -
              5. If the result of running Get Newest Worker algorithm is null, then: -
                  -
                1. Invoke Clear Registration algorithm passing registration as its argument.
                2. -
                -
              6. -
              7. Abort these steps.
              8. -
              -
            4. -
            -
          14. -
          15. Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: -
              -
            1. Reject p with a "SecurityError" exception.
            2. -
            3. Pop the top element from installation queue and installation result handle queue.
            4. -
            5. If the result of running Get Newest Worker algorithm is null, then: -
                -
              1. Invoke Clear Registration algorithm passing registration as its argument.
              2. -
              -
            6. -
            7. Abort these steps.
            8. -
            -
          16. -
          17. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
          18. -
          19. If newestWorker is not null, and newestWorker's script url is equal to registration's registering script url and response is a byte-for-byte match with the script of newestWorker, then: -
              -
            1. Resolve p with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
            2. -
            3. Abort these steps.
            4. -
            -
          20. -
          21. Else: -
              -
            1. Let worker be a new service worker for the script with registration's registering script url.
            2. -
            3. If worker fails to start up, due to parse errors or uncaught errors, then: -
                -
              1. Reject p with the error.
              2. -
              3. Pop the top element from installation queue and installation result handle queue.
              4. -
              5. If the result of running Get Newest Worker algorithm is null, then: -
                  -
                1. Invoke Clear Registration algorithm passing registration as its argument.
                2. -
                -
              6. -
              7. Abort these steps.
              8. -
              -
            4. -
            -
          22. +
          23. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
          24. Invoke Finish Job with job and abort these steps.
          -
        2. -
        3. Invoke Install algorithm, or its equivalent, with client, registration, worker, p, and timeStamp as its arguments.
        4. +
      -
    6. -
    7. Return p.
    8. -
    - - - - -

    Soft Update

    - -

    The user agent may call this as often as it likes to check for updates.

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    Output
    -
    None
    -
    -
      -
    1. Let client be an empty environment settings object.
    2. -
    3. If registration's uninstalling flag is set, then: +
    4. + Else:
        -
      1. Abort these steps.
      2. +
      3. Invoke Set Registration algorithm passing job’s scope url as its argument.
      -
    5. -
    6. If registration's installing worker is not null, then: +
    7. Invoke Update algorithm, or its equivalent, passing job as the argument. +
    +
    +
    +

    Update

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. Let registration be the result of running the Get Registration algorithm passing job’s scope url as the argument. +
    2. + If registration is null or registration’s uninstalling flag is set, then:
        -
      1. Abort these steps.
      2. +
      3. Invoke Reject Job Promise with job and a TypeError. +
      4. Invoke Finish Job with job and abort these steps.
      -
    3. -
    4. Invoke Update algorithm, or its equivalent, with client, registration as its argument.
    5. -
    - -

    Inspect whether the promise returned from Update algorithm should be returned to the caller (either UA internal context or reg.update()).

    - - - -

    Install

    - -

    The algorithm uses installation queue to synchronize the set of multiple installation jobs. Implementers may use it or other synchronization primitives and methods to satisfy this requirement.

    - - -
    -
    Input
    -
    client, a service worker client
    -
    registration, a service worker registration
    -
    worker, a service worker
    -
    registrationPromise, a promise
    -
    timeStamp, a timestamp
    -
    Output
    -
    none
    -
    -
      -
    1. Let installFailed be false.
    2. -
    3. CheckPriority: If the value of the top element of installation queue matches timeStamp, then: +
    4. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument. +
    5. + If job’s job type is update, and newestWorker’s script url is not job’s script url, then:
        -
      1. Pop the top element from installation queue.
      2. +
      3. Invoke Reject Job Promise with job and a TypeError. +
      4. Invoke Finish Job with job and abort these steps.
      -
    6. -
    7. Else: +
    8. + Switching on job’s worker type, run these substeps with the following options: +
      +
      "classic" +
      +

      Fetch a classic worker script given job’s serialized script url, job’s client, and "serviceworker".

      +
      "module" +
      +

      Fetch a module script tree given job’s serialized script url, "omit", "serviceworker", and job’s client.

      +
      +

      To set up the request given request, run the following steps:

        -
      1. Wait until the top element of installation queue is popped.
      2. -
      3. Jump to the step labeled CheckProirity.
      4. +
      5. + Append `Service-Worker`/`script` to request’s header list. +

        See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.

        +
      6. Set request’s skip service worker flag and request’s redirect mode to "error". +
      7. + If newestWorker is not null and registration’s last update check time is not null, then: +
          +
        1. If the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, or force bypass cache flag is set, set request’s cache mode to "reload". +
        +

        Even if the cache mode is not set to "reload", the user agent obeys Cache-Control header’s max-age value in the network layer to determine if it should bypass the browser cache.

      -

      Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

      -
    9. -
    10. Run the following substeps atomically: +

      To validate the response given response, run the following steps:

        -
      1. If registration's installing worker is not null, then: -
          -
        1. Terminate registration's installing worker.
        2. -
        3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
        4. -
        5. The user agent may abort any in-flight requests triggered by registration's installing worker.
        6. -
        -
      2. -
      3. Set registration's installing worker to worker.
      4. -
      5. Run the Update State algorithm passing registration's installing worker and installing as the arguments.
      6. -
      7. Assert: registrationPromise is not null.
      8. -
      9. Resolve registrationPromise with a ServiceWorkerRegistration object, setting its service worker client to client, which represents registration.
      10. -
      11. Queue a task to fire a simple event named updatefound at all the ServiceWorkerRegistration objects that represent registration for all the service worker clients whose creation url matches registration's scope url.
      12. -
      13. Queue a task to run the following substeps: -
          -
        1. Let installingWorker be registration's installing worker.
        2. -
        3. Run a worker, if not running, for a script with installingWorker's script url and installingWorker's environment settings object.
        4. -
        5. Fire an event named install using InstallEvent interface at installingWorker's environment settings object's global object.
        6. -
        7. Let event be null.
        8. -
        9. For each event listener invoked: -
            -
          1. If any uncaught runtime script error occurs, then: -
              -
            1. Report the error for the script per the runtime script errors handling.
            2. -
            3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
            4. -
            5. Set registration's installing worker to null.
            6. -
            7. Pop the top element from installation result handle queue.
            8. -
            9. If the result of running Get Newest Worker algorithm is null, then: -
                -
              1. Invoke Clear Registration algorithm passing registration as its argument.
              2. -
              -
            10. -
            11. Abort these steps.
            12. -
            -
          2. -
          3. Set event to the event for which this event listener was invoked.
          4. -
          -
        10. -
        11. Let p be waiting for all of event's extend lifetime promises.
        12. -
        13. Wait until p settles.
        14. -
        15. If p rejected, then: -
            -
          1. Set installFailed to true.
          2. -
          -
        16. -
        17. Else if p resolved with a value, then: -
            -
          1. Do nothing.
          2. -
          -
        18. -
        -
      14. +
      15. + Extract a MIME type from the response’s header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
          +
        1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
        2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        3. Invoke Finish Job with job. +
        4. Return false and abort these steps. +
        +
      16. + Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response’s header list. +

        See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.

        +
      17. + If serviceWorkerAllowed is failure, then: +
          +
        1. Invoke Reject Job Promise with job and a TypeError. +
        2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        3. Invoke Finish Job with job. +
        4. Return false and abort these steps. +
        +
      18. Let scopeURL be registration’s scope url. +
      19. Let maxScopeString be null. +
      20. + If serviceWorkerAllowed is null, then: +
          +
        1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script’s file name, in job’s script url’s path (including empty strings), separated from each other by "/". +
        +
      21. + Else: +
          +
        1. Let maxScope be the result of parsing serviceWorkerAllowed with job’s script url. +
        2. Set maxScopeString to "/" concatenated with the strings in maxScope’s path (including empty strings), separated from each other by "/". +
        +
      22. Let scopeString be "/" concatenated with the strings in scopeURL’s path (including empty strings), separated from each other by "/". +
      23. If scopeString starts with maxScopeString, do nothing. +
      24. + Else: +
          +
        1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
        2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        3. Invoke Finish Job with job. +
        4. Return false and abort these steps. +
        +
      25. If response’s cache state is not "local", set registration’s last update check time to the current time. +
      26. Return true.
      -
    11. -
    12. CheckResultHandlePriority: If the value of the top element of installation result handle queue matches timeStamp, then: +

      If the algorithm asynchronously completes with null, then:

        -
      1. Pop the top element from installation result handle queue.
      2. +
      3. Invoke Reject Job Promise with job and a TypeError. +
      4. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      5. Invoke Finish Job with job and abort these steps.
      -
    13. -
    14. Else: +

      +

      Else, continue the rest of these steps after the algorithm’s asynchronous completion, with script being the asynchronous completion value.

      +
    15. + If newestWorker is not null, newestWorker’s script url equals job’s script url with the exclude fragments flag set, and script is a byte-for-byte match with newestWorker’s script resource, then:
        -
      1. Wait until the top element of installation result handle queue is popped.
      2. -
      3. Jump to the step labeled CheckResultHandlePriority.
      4. +
      5. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
      6. Invoke Finish Job with job and abort these steps.
      -

      Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.

      -
    16. -
    17. Run the following substeps atomically: +
    18. + Else:
        -
      1. Wait for the task queued by the step 4.7 to have executed.
      2. -
      3. If registration's installing worker is null, then: -
          -
        1. Abort these steps.
        2. -
        -
      4. -
      5. If installFailed is true, then: -
          -
        1. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
        2. -
        3. Set registration's installing worker to null.
        4. -
        5. If the result of running Get Newest Worker algorithm is null, then: -
            -
          1. Invoke Clear Registration algorithm passing registration as its argument.
          2. -
          -
        6. -
        7. Abort these steps.
        8. -
        -
      6. -
      7. If registration's waiting worker is not null, then: -
          -
        1. Terminate registration's waiting worker.
        2. -
        3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
        4. -
        5. The user agent may abort in-flight requests triggered by registration's waiting worker.
        6. -
        -
      8. -
      9. Set registration's waiting worker to registration's installing worker.
      10. -
      11. Set registration's installing worker to null.
      12. -
      13. Run the Update State algorithm passing registration's waiting worker and installed as the arguments.
      14. -
      15. If registration's uninstalling flag is set before timeStamp, then: -
          -
        1. Wait until a Record {[[key]], [[value]]} entry of its scope to registration map where registration's scope url matches entry.[[key]] is deleted.
        2. -
        3. Set a newly-created Record {[[key]]: registration's scope url, [[value]]: registration} to scope to registration map.
        4. -
        5. Unset registration's uninstalling flag.
        6. -
        -
      16. -
      17. If registration's waiting worker's skip waiting flag is set, then: -
          -
        1. For each service worker client serviceWorkerClient whose creation url matches registration's scope url: -
            -
          1. Let exitingWorker be the active worker that controls serviceWorkerClient.
          2. -
          3. If exitingWorker is not null, then: -
              -
            1. Wait for exitingWorker to finish handling any in-progress requests. -
            2. -
            3. Terminate exitingWorker.
            4. -
            5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
            6. -
            -
          4. -
          -
        2. -
        3. Run Activate algorithm, or its equivalent, passing registration as the argument.
        4. -
        5. Abort these steps.
        6. -
        -
      18. +
      19. Let worker be a new service worker. +
      20. Generate a unique opaque string and set worker’s id to the value. +
      21. Set worker’s script url to job’s script url, worker’s script resource to script, and worker’s type to job’s worker type. +
      22. Invoke Run Service Worker algorithm with worker as the argument. +
      23. + If an uncaught runtime script error occurs during the above step, then: +
          +
        1. Invoke Reject Job Promise with job and a TypeError. +
        2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        3. Invoke Finish Job with job and abort these steps. +
      -
    19. -
    20. Wait until no service worker client is using registration or registration's waiting worker's skip waiting flag is set.
    21. -
    22. If registration's waiting worker waitingWorker is not null and waitingWorker's skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument.
    23. -
    -
    -
    - - -

    Activate

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    Output
    -
    None
    -
    -
      -
    1. Run the following substeps atomically: +
    2. Invoke Install algorithm, or its equivalent, with job, worker, and registration as its arguments. +
    +
    +
    +

    Soft Update

    +

    The user agent may call this as often as it likes to check for updates.

    +
    +
    Input +
    registration, a service worker registration +
    force bypass cache flag, an optional flag unset by default +

    Implementers may use the force bypass cache flag to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs.

    +
    Output +
    None +
    +
      +
    1. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
    2. If newestWorker is null, abort these steps. +
    3. Let job be the result of running Create Job with update, registration’s scope url, newestWorker’s script url, a new promise, and null. +
    4. Set job’s worker type to newestWorker’s type. +
    5. Set job’s force bypass cache flag if its force bypass cache flag is set. +
    6. + Run the following substep in parallel:
        -
      1. Let activateFailed be false.
      2. -
      3. Let activatingWorker be registration's waiting worker.
      4. -
      5. Let exitingWorker be registration's active worker.
      6. -
      7. If activatingWorker is null, then: +
      8. Invoke Schedule Job with job. +
      +
    +
    +
    +

    Install

    +
    +
    Input +
    job, a job +
    worker, a service worker +
    registration, a service worker registration +
    Output +
    none +
    +
      +
    1. Let installFailed be false. +
    2. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
    3. Set registration’s installing worker to worker. +
    4. Run the Update State algorithm passing registration’s installing worker and installing as the arguments. +
    5. Assert: job’s promise is not null. +
    6. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
    7. Queue a task to fire a simple event named updatefound at all the ServiceWorkerRegistration objects for all the service worker clients whose creation url matches registration’s scope url and all the service workers whose containing service worker registration is registration. +
    8. Let installingWorker be registration’s installing worker. +
    9. Invoke Run Service Worker algorithm with installingWorker as the argument. +
    10. + Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the InstallEvent interface, with the event type install, which does not bubble, is not cancelable, and has no default action. +
      2. Dispatch e at installingWorker’s environment settings object’s global object globalObject. +
      3. Let extendLifetimePromises be an empty array. +
      4. + For each event listener invoked: +
          +
        1. + If any uncaught runtime script error occurs, then:
            -
          1. Abort these steps.
          2. +
          3. Report the error for the script per the runtime script errors handling. +
          4. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
          5. Set registration’s installing worker to null. +
          6. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
          7. Invoke Finish Job with job and abort these steps.
          -
        2. -
        3. If exitingWorker is not null, then: -
            -
          1. Wait for exitingWorker to finish handling any in-progress requests. -
          2. -
          3. Terminate exitingWorker.
          4. -
          5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
          6. -
          -
        4. -
        5. Set registration's active worker to activatingWorker.
        6. -
        7. Set registration's waiting worker to null.
        8. -
        9. Run the Update State algorithm passing registration's active worker and activating as the arguments.
        10. -
        11. For each service worker client client whose creation url matches registration's scope url: -
            -
          1. If client is a window client, then: -
              -
            1. Unassociate client's responsible document from its application cache, if it has one.
            2. -
            -
          2. -
          3. Else if client is a shared worker client, then: -
              -
            1. Unassociate client's global object from its application cache, if it has one.
            2. -
            -
          4. -
          -

          Resources will now use the service worker registration instead of the existing application cache.

          -
        12. -
        13. Queue a task to fire a simple event named controllerchange at all the ServiceWorkerContainer objects for all the service worker clients which use registration.
        14. -
        15. Queue a task to run the following substeps: -
            -
          1. Let activeWorker be registration's active worker.
          2. -
          3. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
          4. -
          5. Fire an event named activate using ExtendableEvent interface at activeWorker's environment settings object's global object.
          6. -
          7. Let event be null.
          8. -
          9. For each event listener invoked: -
              -
            1. If any uncaught runtime script error occurs, then: -
                -
              1. Report the error for the script per the runtime script errors handling.
              2. -
              3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
              4. -
              5. Set registration's active worker to null.
              6. -
              7. Abort these steps.
              8. -
              -
            2. -
            3. Set event to the event for which this event listener was invoked.
            4. -
            -
          10. -
          11. Let p be waiting for all of event's extend lifetime promises.
          12. -
          13. Wait until p settles.
          14. -
          15. If p rejected, then: -
              -
            1. Set activateFailed to true.
            2. -
            -
          16. -
          17. Else if p resolved with a value, then: -
              -
            1. Do nothing.
            2. -
            -
          18. -
          -
        16. -
        17. Wait for the task queued by the previous step to have executed.
        18. -
        19. If activateFailed is true, then: -
            -
          1. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
          2. -
          3. Set registration's active worker to null.
          4. -
          5. Abort these steps.
          6. -
          -
        20. -
        21. Run the Update State algorithm passing registration's active worker and activated as the arguments.
        22. +
        23. Let eventObject be the first argument passed to this event listener. +
        24. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
        +
      5. Let p be waiting for all of extendLifetimePromises. +
      6. + Run the following substeps in parallel: +
          +
        1. Wait until p settles. +
        2. If p rejected, set installFailed to true. +
        3. Else if p resolved with a value, do nothing. +
      -
    11. -
    - - - - -

    Handle Fetch

    - -

    The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

    - - -
    -
    Input
    -
    request, a request
    -
    Output
    -
    response, a response
    -
    -
      -
    1. Let handleFetchFailed be false.
    2. -
    3. Let respondWithEntered be false.
    4. -
    5. Let eventCanceled be false.
    6. -
    7. Let r be a new Request object associated with request.
    8. -
    9. Let headersObject be r's headers attribute value.
    10. -
    11. Set headersObject's guard to immutable.
    12. -
    13. Let response be null.
    14. -
    15. Let registration be null.
    16. -
    17. Let client be request's client.
    18. -
    19. Assert: request's context is not serviceworker.
    20. -
    21. If request is a potential client request, then: -
        -
      1. Return null.
      2. -
      -
    22. -
    23. Else if request is a client request, then: -
        -
      1. If the navigation triggering request was initiated with a shift+reload or equivalent, then: -
          -
        1. Return null.
        2. -
        -
      2. -
      3. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing r's url attribute value as the argument.
      4. -
      5. If registration is null or registration's active worker is null, return null.
      6. -
      7. Set client's active worker to registration's active worker.
      8. +

        If task is discarded or the script has been aborted by the termination of installingWorker, set installFailed to true.

        +
      9. Wait for task to have executed or been discarded. +
      10. + If installFailed is true, then: +
          +
        1. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
        2. Set registration’s installing worker to null. +
        3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        4. Invoke Finish Job with job and abort these steps.
        -

        From this point, the service worker client starts to use its active worker's containing service worker registration.

        -
      11. -
      12. Else if request is a resource request, then: +
      13. Set registration’s installing worker’s imported scripts updated flag. +
      14. + If registration’s waiting worker is not null, then:
          -
        1. If client's active worker in non-null, then: -
            -
          1. Set registration to client's active worker's containing service worker registration.
          2. -
          -
        2. -
        3. Else: -
            -
          1. Return null.
          2. -
          -
        4. +
        5. Terminate registration’s waiting worker. +
        6. Run the Update State algorithm passing registration’s waiting worker and redundant as the arguments. +
        7. The user agent may abort in-flight requests triggered by registration’s waiting worker.
        -
      15. -
      16. Let matchedWorker be registration's active worker.
      17. -
      18. If matchedWorker's state is activating, then: +
      19. Set registration’s waiting worker to registration’s installing worker. +
      20. Set registration’s installing worker to null. +
      21. Run the Update State algorithm passing registration’s waiting worker and installed as the arguments. +
      22. + If registration’s waiting worker’s skip waiting flag is set, then:
          -
        1. Wait for matchedWorker's state to become activated.
        2. -
        3. If matchedWorker's activation fails, then: -
            -
          1. Return null.
          2. -
          -
        4. +
        5. Run Activate algorithm, or its equivalent, passing registration as the argument. +
        6. Invoke Finish Job with job and abort these steps.
        -
      23. -
      24. Queue a task to run the following substeps: +
      25. Invoke Finish Job with job. +
      26. Wait for all the tasks queued by Update State invoked in this algorithm have executed. +
      27. Wait until no service worker client is using registration or registration’s waiting worker’s skip waiting flag is set. +
      28. If registration’s waiting worker waitingWorker is not null and waitingWorker’s skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument. +
      +
    +
    +

    Activate

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    None +
    +
      +
    1. Let activatingWorker be registration’s waiting worker. +
    2. Let exitingWorker be registration’s active worker. +
    3. If activatingWorker is null, abort these steps. +
    4. + If exitingWorker is not null, then:
        -
      1. Let activeWorker be registration's active worker.
      2. -
      3. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
      4. -
      5. Fire an event named fetch, using FetchEvent interface, with request attribute initialized to r, client attribute initialized to client of the request, in the form of Client object, and isReload initialized to true if event was dispatched with the user's intention for the page reload, and false otherwise, at activeWorker's environment settings object's global object.
      6. -
      7. For each event listener invoked: -
          -
        1. If any uncaught runtime script error occurs, then: -
            -
          1. Report the error for the script per the runtime script errors handling.
          2. -
          3. Abort these steps.
          4. -
          -
        2. -
        3. Let event be the event for which this event listener was invoked.
        4. -
        5. If event's respond-with entered flag is set, then: -
            -
          1. Set respondWithEntered to true.
          2. -
          -
        6. -
        7. If event's wait to respond flag is set, then: -
            -
          1. Wait until event's wait to respond flag is unset.
          2. -
          3. If event's respond-with error flag is set, then: -
              -
            1. Set handleFetchFailed to true.
            2. -
            -
          4. -
          5. Else: -
              -
            1. If the argument passed into the event's respondWith(r) method arg is a Response object, then: -
              1. Set response to arg.
              -
            2. -
            3. Else: -
                -
              1. Set response to the value which arg resolved with.
              2. -
              -
            4. -
            -
          6. -
          -
        8. -
        9. If event's canceled flag is set, then: -
            -
          1. Set eventCanceled to true.
          2. -
          -
        10. -
        -
      8. +
      9. Wait for exitingWorker to finish handling any in-progress requests. +
      10. Terminate exitingWorker. +
      11. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
      -
    5. -
    6. Wait for the task queued by the previous step to have executed.
    7. -
    8. If respondWithEntered is false, then: +
    9. Set registration’s active worker to activatingWorker. +
    10. Set registration’s waiting worker to null. +
    11. + Run the Update State algorithm passing registration’s active worker and activating as the arguments. +

      Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated.

      +
    12. + For each service worker client client whose creation url matches registration’s scope url:
        -
      1. If eventCanceled is true, then: -
          -
        1. Return a network error and run the following substeps in parallel.
        2. -
        -
      2. -
      3. Else: -
          -
        1. Return null and run the following substeps in parallel.
        2. -
        -
      4. -
      5. If request is a client request, then: -
          -
        1. Invoke Soft Update algorithm, or its equivalent, with registration.
        2. -
        -
      6. -
      7. Abort these steps.
      8. +
      9. If client is a window client, unassociate client’s responsible document from its application cache, if it has one. +
      10. Else if client is a shared worker client, unassociate client’s global object from its application cache, if it has one.
      -
    13. -
    14. If handleFetchFailed is true, then: +

      Resources will now use the service worker registration instead of the existing application cache.

      +
    15. + For each service worker client client who is using registration:
        -
      1. Return a network error and run the following substeps in parallel.
      2. -
      3. If request is a client request, then: -
          -
        1. Invoke Soft Update algorithm, or its equivalent, with registration.
        2. -
        -
      4. +
      5. Set client’s active worker to registration’s active worker. +
      6. Invoke Notify Controller Change algorithm with client as the argument.
      -
    16. -
    17. Else: +
    18. Let activeWorker be registration’s active worker. +
    19. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    20. + Queue a task task to run the following substeps:
        -
      1. Return a response represented by response and run the following substeps in parallel.
      2. -
      3. If request is a client request, then: +
      4. Create a trusted event e that uses the ExtendableEvent interface, with the event type activate, which does not bubble, is not cancelable, and has no default action. +
      5. Dispatch e at activeWorker’s environment settings object’s global object. +
      6. Let extendLifetimePromises be an empty array. +
      7. + For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, report the error for the script per the runtime script errors handling. +
        2. Let eventObject be the first argument passed to this event listener. +
        3. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
        +
      8. Let p be waiting for all of extendLifetimePromises. +
      +
    21. Wait for task to have executed and p defined in task has settled, or task to have been discarded or the script to have been aborted by the termination of activeWorker. +
    22. Run the Update State algorithm passing registration’s active worker and activated as the arguments. +
    +
    +
    +

    Run Service Worker

    +
    +
    Input +
    serviceWorker, a service worker +
    Output +
    None +
    +
      +
    1. Let script be serviceWorker’s script resource. +
    2. Assert: script is not null. +
    3. If serviceWorker is already running, abort these steps. +
    4. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context. +
    5. + Call the JavaScript InitializeHostDefinedRealm() abstract operation with the following customizations: + +
    6. Let workerEventLoop be a newly created event loop. +
    7. Let workerGlobalScope be realmExecutionContext’s global object. +
    8. + Let settingsObject be a new environment settings object whose algorithms are defined as follows: +
      +
      The realm execution context +
      Return realmExecutionContext. +
      The global object +
      Return workerGlobalScope. +
      The responsible event loop +
      Return workerEventLoop. +
      The referrer source +
      Return serviceWorker’s script url. +

      Remove this definition after sorting out the referencing sites.

      +
      The API URL character encoding +
      Return UTF-8. +
      The API base URL +
      Return serviceWorker’s script url. +
      The origin and effective script origin +
      Return its registering service worker client’s origin. +
      The creation URL +
      Return workerGlobalScope’s url. +
      The HTTPS state +
      Return workerGlobalScope’s HTTPS state. +
      +
    9. Set workerGlobalScope’s url to serviceWorker’s script url. +
    10. Set workerGlobalScope’s HTTPS state to serviceWorker’s script resource’s HTTPS state. +
    11. Set workerGlobalScope’s type to serviceWorker’s type. +
    12. Create a new WorkerLocation object and associate it with workerGlobalScope. +
    13. If serviceWorker is an active worker, and there are any tasks queued in serviceWorker’s containing service worker registration’s task queues, queue them to serviceWorker’s event loop’s task queues in the same order using their original task sources. +
    14. + If script is a classic script, then run the classic script script. Otherwise, it is a module script; run the module script script. +

      In addition to the usual possibilities of returning a value or failing due to an exception, this could be prematurely aborted by the kill a worker or terminate a worker algorithms.

      +
    15. + If script’s has ever been evaluated flag is unset, then: +
        +
      1. + Set workerGlobalScope’s associated service worker’s set of event types to handle to the set of event types created from settingsObject’s global object’s associated list of event listeners' event types. +

        If the global object’s associated list of event listeners does not have any event listener added at this moment, the service worker’s set of event types to handle is set to an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script.

        +
      2. Set script’s has ever been evaluated flag. +
      +
    16. Run the responsible event loop specified by settingsObject until it is destroyed. +
    17. Empty workerGlobalScope’s list of active timers. +
    +
    +
    +

    Terminate Service Worker

    +
    +
    Input +
    serviceWorker, a service worker +
    Output +
    None +
    +
      +
    1. If serviceWorker is not running, abort these steps. +
    2. Let serviceWorkerGlobalScope be serviceWorker environment settings object’s global object. +
    3. Set serviceWorkerGlobalScope’s closing flag to true. +
    4. + If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in serviceWorkerGlobalScope’s event loop’s task queues, queue them to serviceWorker’s containing service worker registration’s corresponding task queues in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from serviceWorkerGlobalScope’s event loop’s task queues without processing them. +

      This effectively means that the fetch events and the other functional events such as push events are backed up by the registration’s task queues while the other tasks including message events are discarded.

      +
    5. Abort the script currently running in serviceWorker. +
    +
    +
    +

    Handle Fetch

    +

    The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

    +
    +
    Input +
    request, a request +
    Output +
    response, a response +
    +
      +
    1. Let handleFetchFailed be false. +
    2. Let respondWithEntered be false. +
    3. Let eventCanceled be false. +
    4. Let r be a new Request object associated with request. +
    5. Let headersObject be r’s headers attribute value. +
    6. Set headersObject’s guard to immutable. +
    7. Let response be null. +
    8. Let registration be null. +
    9. Let client be the service worker client that corresponds to request’s client. +
    10. Assert: request’s destination is not "serviceworker". +
    11. + If request is a potential-navigation-or-subresource request, then: +
        +
      1. Return null. +
      +
    12. + Else if request is a non-subresource request, then: +

      If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration.

      +
        +
      1. If client is not a secure context, return null. +
      2. If request is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null. +
      3. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing request’s url as the argument. +
      4. If registration is null or registration’s active worker is null, return null. +
      5. Set client’s active worker to registration’s active worker. +
      +

      From this point, the service worker client starts to use its active worker’s containing service worker registration.

      +
    13. + Else if request is a subresource request, then: +
        +
      1. If client’s active worker is non-null, set registration to client’s active worker’s containing service worker registration. +
      2. Else, return null. +
      +
    14. Let activeWorker be registration’s active worker. +
    15. + If activeWorker’s set of event types to handle does not contain fetch, return null. +

      To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker’s global during the very first script execution.

      +
    16. If activeWorker’s state is activating, wait for activeWorker’s state to become activated. +
    17. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    18. + Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the FetchEvent interface, with the event type fetch, which does not bubble and has no default action. +
      2. Let the request attribute of e be initialized to r. +
      3. Let the clientId attribute of e be initialized to client’s id if request is not a non-subresource request, and to null otherwise. +
      4. Let the isReload attribute of e be initialized to true if request’s client is a window client and the event was dispatched with the user’s intention for the page reload, and false otherwise. +
      5. Dispatch e at activeWorker’s environment settings object’s global object. +
      6. + For each event listener invoked: +
          +
        1. + If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling. +
          2. Abort these steps. +
          +
        2. Let event be the event for which this event listener was invoked. +
        3. If event’s respond-with entered flag is set, set respondWithEntered to true. +
        4. + If event’s wait to respond flag is set, then:
            -
          1. Invoke Soft Update algorithm, or its equivalent, with registration.
          2. +
          3. Wait until event’s wait to respond flag is unset. +
          4. If event’s respond-with error flag is set, set handleFetchFailed to true. +
          5. Else, set response to event’s potential response.
          -
        5. +
        6. If event’s canceled flag is set, set eventCanceled to true. +
      -
    19. -
    - - - - -

    Handle Functional Event

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    callbackSteps, an algorithm
    -
    Output
    -
    None
    -
    -
      -
    1. Queue a task to run Handle Functional Event On Scheduled Task algorithm with registration and callbackSteps.
    2. -
    -
    -

    Event loop and task queuing model for this algorithm will be specified.

    -
    - - -

    Handle Functional Event On Scheduled Task

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    callbackSteps, an algorithm
    -
    Output
    -
    None
    -
    -
      -
    1. Assert: a Record with the [[value]] equals to registration is contained in scope to registration map.
    2. -
    3. Assert: registration's active worker is not null.
    4. -
    5. Let activeWorker be registration's active worker.
    6. -
    7. Run a worker, if not running, for a script with activeWorker's script url and activeWorker's environment settings object.
    8. -
    9. Invoke callbackSteps, defined by the caller of the algorithm which queued this task, with activeWorker's environment settings object's global object as its argument.
    10. -
    11. Return.
    12. -
    -
    -
    - - -

    Handle Service Worker Client Unload

    - -

    The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

    - - -
    -
    Input
    -
    client, a service worker client
    -
    Output
    -
    None
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. Let registration be the service worker registration used by client.
    4. -
    5. If registration is null, then: +

      If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

      +

      The task must use activeWorker’s event loop and the handle fetch task source.

      +
    6. Wait for task to have executed or been discarded. +
    7. + If respondWithEntered is false, then:
        -
      1. Abort these steps.
      2. +
      3. If eventCanceled is true, return a network error and continue running these substeps in parallel. +
      4. Else, return null and continue running these substeps in parallel. +
      5. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
      6. Abort these steps.
      -
    8. -
    9. If any other service worker client is using registration, then: +
    10. + If handleFetchFailed is true, then:
        -
      1. Abort these steps.
      2. +
      3. Return a network error and continue running these substeps in parallel. +
      4. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
      -
    11. -
    12. If registration's uninstalling flag is true, then: +
    13. + Else:
        -
      1. Invoke Clear Registration algorithm passing registration as its argument.
      2. -
      3. Abort these steps.
      4. +
      5. Return response and continue running these substeps in parallel. +
      6. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
      -
    14. -
    15. If registration.waiting is not null: +
    +
    +
    +

    Handle Foreign Fetch

    +

    The Handle Foreign Fetch algorithm is the entry point for the fetch handling handed to the service worker context to handle foreign fetch requests.

    +

    This needs an extra step in the HTTP fetch algorithm in between step 3 and 4, to call this algorithm for all requests if response is null at that point.

    +
    +
    Input +
    request, a request +
    Output +
    response, a response +
    +
      +
    1. Let handleFetchFailed be false. +
    2. Let respondWithEntered be false. +
    3. Let eventCanceled be false. +
    4. + If request is not a subresource request, return null and abort these steps. +

      Foreign fetch only allows intercepting of subresource requests. Navigation requests can be intercepted by the regular fetch event anyway, so there is no benefit to supporting those requests here as well.

      +
    5. If request’s client is not a secure context, return null and abort these steps. +
    6. Let activeWorker be the result of running the Match Service Worker for Foreign Fetch algorithm passing request’s url as the argument. +
    7. If activeWorker is null, return null. +
    8. + If activeWorker’s state is activating, then:
        -
      1. Run Activate algorithm, or its equivalent, with registration at the argument.
      2. +
      3. Wait for activeWorker’s state to become activated.
      -
    9. -
    - - - - -

    Unregister

    - - -
    -
    Input
    -
    client, a service worker client
    -
    scope, an absolute URL
    -
    Output
    -
    promise, a promise
    -
    -
      -
    1. Let promise be a new promise.
    2. -
    3. Run the following substeps in parallel: +
    4. If activeWorker’s origin is the same as request’s origin, return null. +
    5. Let originMatches be false. +
    6. If activeWorker’s list of foreign fetch origins is empty, set originMatches to true. +
    7. + For each origin in activeWorker’s list of foreign fetch origins: +
        +
      1. If origin is equal to request’s origin, set originMatches to true. +
      +
    8. If originMatches is false, return null. +
    9. Let r be a new Request object associated with request. +
    10. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    11. + Queue a task task to run the following substeps:
        -
      1. If the origin of scope is not client's origin, then: +
      2. Create a trusted event e that uses the ForeignFetchEvent interface, with the event type foreignfetch, which does not bubble and has no default action. +
      3. Let the request attribute of e be initialized to r. +
      4. Dispatch e at activeWorker’s environment settings object’s global object. +
      5. + For each event listener invoked: +
          +
        1. + If any uncaught runtime script error occurs, then:
            -
          1. Reject promise with a "SecurityError" exception.
          2. -
          3. Abort these steps.
          4. +
          5. Report the error for the script per the runtime script errors handling. +
          6. Abort these steps.
          -
        2. -
        3. Let registration be the result of running Get Registration algorithm passing scope as the argument.
        4. -
        5. If registration is null, then: +
        6. Let event be the event for which this event listener was invoked. +
        7. + If event’s respond-with entered flag is set, then:
            -
          1. Resolve promise with false.
          2. -
          3. Abort these steps.
          4. +
          5. Set respondWithEntered to true.
          -
        8. -
        9. Set registration's uninstalling flag.
        10. -
        11. Resolve promise with true.
        12. -
        13. If no service worker client is using registration, then: +
        14. + If event’s wait to respond flag is set, then:
            -
          1. If registration's uninstalling flag is unset, then: -
              -
            1. Abort these steps.
            2. -
            -
          2. -
          3. Invoke Clear Registration algorithm passing registration as its argument.
          4. +
          5. Wait until event’s wait to respond flag is unset. +
          +
        15. Let internalResponse be event’s potential response. +
        16. If internalResponse is a filtered response, set internalResponse to internalResponse’s internal response. +
        17. If event’s respond-with error flag is set, set handleFetchFailed to true. +
        18. + Else if event’s origin is null: +
            +
          1. If event’s list of exposed headers is not empty, set handleFetchFailed to true. +
          2. Else if event’s potential response is a opaque-redirect filtered response, set response to event’s potential response. +
          3. Else set response to an opaque filtered response of internalResponse. +
          +
        19. Else if event’s origin is not equal to request’s origin, set handleFetchFailed to true. +
        20. Else if event’s potential response is an opaque filtered response or is an opaque-redirect filtered response, set response to event’s potential response. +
        21. Else if request’s response tainting is "opaque", set response to an opaque filtered response of internalResponse. +
        22. + Else: +
            +
          1. Let headers be event’s list of exposed headers. +
          2. If response is a CORS filtered response, remove from internalResponse’s CORS-exposed header-names list all values not in headers. +
          3. Else set internalResponse’s CORS-exposed header-names list to headers. +
          4. Set response to a CORS filtered response of internalResponse.
          -
        23. +
        24. + If event’s canceled flag is set, then: +
            +
          1. Set eventCanceled to true. +
          +
      -
    12. -
    13. Return promise.
    14. -
    -
    -
    - - -

    Set Registration

    - - -
    -
    Input
    -
    scope, an absolute URL
    -
    Output
    -
    registration, a service worker registration
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. Let scopeString be serialized scope with the exclude fragment flag set.
    4. -
    5. Let registration be a new service worker registration whose scope url is set to scope.
    6. -
    7. Set a newly-created Record {[[key]]: scopeString, [[value]]: registration} to scope to registration map.
    8. -
    9. Return registration.
    10. -
    -
    -
    - - -

    Clear Registration

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    Output
    -
    None
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. If registration's installing worker is not null, then: +

      If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

      +

      The task must use activeWorker’s event loop and the handle fetch task source.

      +
    4. Wait for task to have executed or been discarded. +
    5. + If respondWithEntered is false, then:
        -
      1. Terminate registration's installing worker.
      2. -
      3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      4. -
      5. Set registration's installing worker to null.
      6. -
      7. The user agent may abort in-flight requests triggered by registration's installing worker.
      8. +
      9. + If eventCanceled is true, then: +
          +
        1. Return a network error. +
        +
      10. + Else: +
          +
        1. Return null. +
      -
    6. -
    7. If registration's waiting worker is not null, then: +
    8. + If handleFetchFailed is true, then:
        -
      1. Terminate registration's waiting worker.
      2. -
      3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
      4. -
      5. Set registration's waiting worker to null.
      6. -
      7. The user agent may abort in-flight requests triggered by registration's waiting worker.
      8. +
      9. Return a network error.
      -
    9. -
    10. If registration's active worker is not null, then: +
    11. + Else:
        -
      1. Terminate registration's active worker.
      2. -
      3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
      4. -
      5. Set registration's active worker to null.
      6. -
      7. The user agent may abort in-flight requests triggered by registration's active worker.
      8. +
      9. Return response.
      -
    12. -
    13. Delete a Record {[[key]], [[value]]} entry of its scope to registration map where registration's scope url matches entry.[[key]].
    14. -
    -
    -
    - - -

    Update State

    - - -
    -
    Input
    -
    worker, a service worker
    -
    state, a service worker's state
    -
    Output
    -
    None
    -
    -
      -
    1. Set worker's state to state.
    2. -
    3. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker for all the browsing contexts' Document objects and the ServiceWorkerGlobalScope object represented by worker.
    4. -
    5. For each serviceWorker in serviceWorkers: +
    +
    +
    +

    Handle Functional Event

    +
    +
    Input +
    registration, a service worker registration +
    callbackSteps, an algorithm +
    Output +
    None +
    +
      +
    1. Assert: a Record with the [[value]] equals to registration is contained in scope to registration map. +
    2. Assert: registration’s active worker is not null. +
    3. Let activeWorker be registration’s active worker. +
    4. + If activeWorker’s set of event types to handle does not contain the event type for this functional event, return. +

      To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker’s global during the very first script execution.

      +
    5. If activeWorker’s state is activating, wait for activeWorker’s state to become activated. +
    6. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    7. + Queue a task task to invoke callbackSteps with activeWorker’s environment settings object’s global object as its argument. +

      The task must use activeWorker’s event loop and the handle functional event task source.

      +
    8. Wait for task to have executed or been discarded. +
    9. If the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
    +
    +
    +

    Handle Service Worker Client Unload

    +

    The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

    +
    +
    Input +
    client, a service worker client +
    Output +
    None +
    +
      +
    1. Run the following steps atomically. +
    2. Let registration be the service worker registration used by client. +
    3. If registration is null, abort these steps. +
    4. If any other service worker client is using registration, abort these steps. +
    5. If registration’s uninstalling flag is set, invoke Clear Registration algorithm passing registration as its argument and abort these steps. +
    6. If registration’s waiting worker is not null, run Activate algorithm, or its equivalent, with registration as the argument. +
    +
    +
    +

    Handle User Agent Shutdown

    +
    +
    Input +
    None +
    Output +
    None +
    +
      +
    1. + For each Record {[[key]], [[value]]} entry of its scope to registration map:
        -
      1. Queue a task to fire a simple event named statechange at serviceWorker.
      2. +
      3. Let registration be entry.[[value]]. +
      4. + If registration’s installing worker installingWorker is not null, then: +
          +
        1. If the result of running Get Newest Worker with registration is installingWorker, invoke Clear Registration with registration and continue to the next iteration of the loop. +
        2. Else, set registration’s installing worker to null. +
        +
      5. + If registration’s waiting worker is not null, run the following substep in parallel: +
          +
        1. Invoke Activate with registration. +
      -
    2. -
    - - - - -

    Match Service Worker Registration

    - - -
    -
    Input
    -
    clientURL, an absolute URL
    -
    Output
    -
    registration, a service worker registration
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. Let clientURLString be serialized clientURL.
    4. -
    5. Let matchingScope be the longest [[key]] in scope to registration map starting with the value of clientURLString.
    6. -
    7. Let matchingScopeURL be the result of parsing matchingScope.
    8. -
    9. Let registration be the result of running Get Registration algorithm passing matchingScopeURL as the argument.
    10. -
    11. If registration is not null and registration's uninstalling flag is set, then: -
        -
      1. Return null.
      2. -
      -
    12. -
    13. Return registration.
    14. -
    -
    -
    - - -

    Get Registration

    - - -
    -
    Input
    -
    scope, an absolute URL
    -
    Output
    -
    registration, a service worker registration
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. Let registration be null.
    4. -
    5. Let scopeString be serialized scope with the exclude fragment flag set.
    6. -
    7. For each Record {[[key]], [[value]]} entry of its scope to registration map: +
    +
    +
    +

    Unregister

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. + If the origin of job’s scope url is not job’s client’s origin, then:
        -
      1. If scopeString matches entry.[[key]], then: -
          -
        1. Set registration to entry.[[value]].
        2. -
        -
      2. +
      3. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      4. Invoke Finish Job with job and abort these steps.
      -
    2. -
    3. Return registration.
    4. -
    - - - - -

    Get Newest Worker

    - - -
    -
    Input
    -
    registration, a service worker registration
    -
    Output
    -
    worker, a service worker
    -
    -
      -
    1. Run the following steps atomically.
    2. -
    3. Let newestWorker be null.
    4. -
    5. If registration's installing worker is not null, then: +
    6. Let registration be the result of running Get Registration algorithm passing job’s scope url as the argument. +
    7. + If registration is null, then:
        -
      1. Set newestWorker to registration's installing worker.
      2. +
      3. Invoke Resolve Job Promise with job and false. +
      4. Invoke Finish Job with job and abort these steps.
      -
    8. -
    9. Else if registration's waiting worker is not null, then: +
    10. Set registration’s uninstalling flag. +
    11. Invoke Resolve Job Promise with job and true. +
    12. + If no service worker client is using registration, then:
        -
      1. Set newestWorker to registration's waiting worker.
      2. +
      3. If registration’s uninstalling flag is unset, invoke Finish Job with job and abort these steps. +
      4. Invoke Clear Registration algorithm passing registration as its argument.
      -
    13. -
    14. Else if registration's active worker is not null, then: +

      When the registration is being used for a client, the deletion of the registration is handled by the Handle Service Worker Client Unload algorithm.

      +
    15. Invoke Finish Job with job. +
    +
    +
    +

    Set Registration

    +
    +
    Input +
    scope, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let scopeString be serialized scope with the exclude fragment flag set. +
    3. Let registration be a new service worker registration whose scope url is set to scope. +
    4. Set a newly-created Record {[[key]]: scopeString, [[value]]: registration} to scope to registration map. +
    5. Return registration. +
    +
    +
    +

    Clear Registration

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    None +
    +
      +
    1. Run the following steps atomically. +
    2. + If registration’s installing worker is not null, then:
        -
      1. Set newestWorker to registration's active worker.
      2. +
      3. Terminate registration’s installing worker. +
      4. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
      5. Set registration’s installing worker to null. +
      6. The user agent may abort in-flight requests triggered by registration’s installing worker.
      -
    3. -
    4. Return newestWorker.
    5. -
    - - - - -

    Query Cache

    - - -
    -
    Input
    -
    request, a Request object
    -
    options, a CacheQueryOptions object, optional
    -
    targetStorage, an array that has [Request, Response] pairs as its elements, optional
    -
    Output
    -
    resultArray, an array that has [Request, Response] pairs as its elements
    -
    -
      -
    1. Let requestArray be an empty array.
    2. -
    3. Let responseArray be an empty array.
    4. -
    5. Let resultArray be an empty array.
    6. -
    7. If options.ignoreMethod is false and request.method is neither "GET" nor "HEAD", then: +
    8. + If registration’s waiting worker is not null, then:
        -
      1. Return resultArray.
      2. +
      3. Terminate registration’s waiting worker. +
      4. Run the Update State algorithm passing registration’s waiting worker and redundant as the arguments. +
      5. Set registration’s waiting worker to null. +
      6. The user agent may abort in-flight requests triggered by registration’s waiting worker.
      -
    9. -
    10. Let cachedURL and requestURL be null.
    11. -
    12. Let serializedCachedURL and serializedRequestURL be null.
    13. -
    14. If the optional argument targetStorage is omitted, then: +
    15. + If registration’s active worker is not null, then:
        -
      1. For each fetching record entry of its request to response map, in key insertion order: -
          -
        1. Set cachedURL to entry.[[key]]'s associated request's url.
        2. -
        3. Set requestURL to request's associated request's url.
        4. -
        5. If options.ignoreSearch is true, then: -
            -
          1. Set cachedURL's query to the empty string.
          2. -
          3. Set requestURL's query to the empty string.
          4. -
          -
        6. -
        7. Set serializedCachedURL to serialized cachedURL.
        8. -
        9. Set serializedRequestURL to serialized requestURL.
        10. -
        11. If options.prefixMatch is true, then: -
            -
          1. Set serializedCachedURL to the substring of itself from the start, with the length of serializedRequestURL.
          2. -
          -
        12. -
        13. If serializedCachedURL matches serializedRequestURL, then: -
            -
          1. Add entry.[[key]] to requestArray.
          2. -
          3. Add entry.[[value]] to responseArray.
          4. -
          -
        14. -
        -
      2. +
      3. Terminate registration’s active worker. +
      4. Run the Update State algorithm passing registration’s active worker and redundant as the arguments. +
      5. Set registration’s active worker to null. +
      6. The user agent may abort in-flight requests triggered by registration’s active worker.
      -
    16. -
    17. Else: +
    18. Delete a Record {[[key]], [[value]]} entry from scope to registration map where registration’s scope url is the result of parsing entry.[[key]]. +
    +
    +
    +

    Update State

    +
    +
    Input +
    worker, a service worker +
    state, a service worker’s state +
    Output +
    None +
    +
      +
    1. Set worker’s state to state. +
    2. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker. +
    3. + For each serviceWorker in serviceWorkers:
        -
      1. For each record in targetStorage: -
          -
        1. Set cachedURL to record[0]'s associated request's url.
        2. -
        3. Set requestURL to request's associated request's url.
        4. -
        5. If options.ignoreSearch is true, then: -
            -
          1. Set cachedURL's query to the empty string.
          2. -
          3. Set requestURL's query to the empty string.
          4. -
          -
        6. -
        7. Set serializedCachedURL to serialized cachedURL.
        8. -
        9. Set serializedRequestURL to serialized requestURL.
        10. -
        11. If options.prefixMatch is true, then: -
            -
          1. Set serializedCachedURL to the substring of itself from the start, with the length of serializedRequestURL.
          2. -
          -
        12. -
        13. If serializedCachedURL matches serializedRequestURL, then: -
            -
          1. Add record[0] to requestArray.
          2. -
          3. Add record[1] to responseArray.
          4. -
          -
        14. -
        -
      2. +
      3. Queue a task to fire a simple event named statechange at serviceWorker. +
      +

      The task must use serviceWorker’s relevant settings object’s responsible event loop and the DOM manipulation task source.

      +
    +
    +
    +

    Notify Controller Change

    +
    +
    Input +
    client, a service worker client +
    Output +
    None +
    +
      +
    1. Assert: client is not null. +
    2. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with. +
    +

    The task must use client’s responsible event loop and the DOM manipulation task source.

    +
    +
    +

    Match Service Worker Registration

    +
    +
    Input +
    clientURL, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let clientURLString be serialized clientURL. +
    3. Let matchingScope be the empty string. +
    4. + Set matchingScope to the longest [[key]] in scope to registration map which the value of clientURLString starts with, if it exists. +

      The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix").

      +
    5. Let parsedMatchingScope be null. +
    6. If matchingScope is not the empty string, set parsedMatchingScope to the result of parsing matchingScope. +
    7. Let registration be the result of running Get Registration algorithm passing parsedMatchingScope as the argument. +
    8. If registration is not null and registration’s uninstalling flag is set, return null. +
    9. Return registration. +
    +
    +
    +

    Match Service Worker for Foreign Fetch

    +
    +
    Input +
    requestURL, a URL +
    Output +
    worker, a service worker +
    +
      +
    1. Run the following steps atomically. +
    2. Let registration be the result of running the Match Service Worker Registration algorithm passing requestURL as the argument. +
    3. If registration is null, return null. +
    4. Let worker be registration’s active worker. +
    5. If worker is null, return null. +
    6. Let requestURLString be the serialized requestURL. +
    7. + For each URL scope in worker’s list of foreign fetch scopes: +
        +
      1. Let scopeString be the serialized scope. +
      2. If requestString starts with scopeString return worker.
      -
    8. -
    9. For each cachedResponse in responseArray with the index index: +
    10. Return null. +
    +
    +
    +

    Get Registration

    +
    +
    Input +
    scope, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let scopeString be the empty string. +
    3. If scope is not null, set scopeString to serialized scope with the exclude fragment flag set. +
    4. Let registration be null. +
    5. + For each Record {[[key]], [[value]]} entry of its scope to registration map:
        -
      1. Let cachedRequest be the indexth element in requestArray.
      2. -
      3. If the result of running cachedResponse.headers object's has(name) method with "Vary" as the argument is false, or options.ignoreVary is true, then: +
      4. If scopeString matches entry.[[key]], set registration to entry.[[value]]. +
      +
    6. Return registration. +
    +
    +
    +

    Get Newest Worker

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    worker, a service worker +
    +
      +
    1. Run the following steps atomically. +
    2. Let newestWorker be null. +
    3. If registration’s installing worker is not null, set newestWorker to registration’s installing worker. +
    4. Else if registration’s waiting worker is not null, set newestWorker to registration’s waiting worker. +
    5. Else if registration’s active worker is not null, set newestWorker to registration’s active worker. +
    6. Return newestWorker. +
    +
    +
    +

    Create Client

    +
    +
    Input +
    client, a service worker client +
    Output +
    clientObject, a Client object +
    +
      +
    1. Let clientObject be a new Client object. +
    2. Set clientObject’s service worker client to client. +
    3. Return clientObject. +
    +
    +
    +

    Create Window Client

    +
    +
    Input +
    client, a service worker client +
    visibilityState, a string +
    focusState, a boolean +
    Output +
    windowClient, a WindowClient object +
    +
      +
    1. Let windowClient be a new WindowClient object. +
    2. Set windowClient’s service worker client to client. +
    3. Set windowClient’s visibility state to visibilityState. +
    4. Set windowClient’s focus state to focusState. +
    5. Return windowClient. +
    +
    +
    +

    Query Cache

    +
    +
    Input +
    request, a Request object +
    options, a CacheQueryOptions object, optional +
    targetStorage, an array that has [Request, Response] pairs as its elements, optional +
    Output +
    resultArray, an array that has [Request, Response] pairs as its elements +
    +
      +
    1. Let requestArray be an empty array. +
    2. Let responseArray be an empty array. +
    3. Let resultArray be an empty array. +
    4. If options.ignoreMethod is false and request.method is neither "GET" nor "HEAD", return resultArray. +
    5. Let cachedURL and requestURL be null. +
    6. Let serializedCachedURL and serializedRequestURL be null. +
    7. + If the optional argument targetStorage is omitted, then: +
        +
      1. + For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Set cachedURL to entry.[[key]]'s associated request’s url. +
        2. Set requestURL to request’s associated request’s url. +
        3. + If options.ignoreSearch is true, then:
            -
          1. Add an array [cachedRequest, cachedResponse] to resultArray.
          2. -
          3. Continue to the next iteration of the loop.
          4. +
          5. Set cachedURL’s query to the empty string. +
          6. Set requestURL’s query to the empty string.
          -
        4. -
        5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
        6. -
        7. Let matchFailed be false.
        8. -
        9. For each f in varyHeaders: +
        10. Set serializedCachedURL to serialized cachedURL. +
        11. Set serializedRequestURL to serialized requestURL. +
        12. + If serializedCachedURL matches serializedRequestURL, then:
            -
          1. If f matches "*", then: -
              -
            1. Continue to the next iteration of the loop.
            2. -
            -
          2. -
          3. If the result of running cachedRequest.headers object's get(name) method with f as the argument does not match the result of running request.headers object's get(name) method with f as the argument, then: -
              -
            1. Set matchFailed to true.
            2. -
            3. Break the loop.
            4. -
            -
          4. +
          5. Add a copy of entry.[[key]] to requestArray. +
          6. Add a copy of entry.[[value]] to responseArray. +
          +
        +
      +
    8. + Else: +
        +
      1. + For each record in targetStorage: +
          +
        1. Set cachedURL to record[0]'s associated request’s url. +
        2. Set requestURL to request’s associated request’s url. +
        3. + If options.ignoreSearch is true, then: +
            +
          1. Set cachedURL’s query to the empty string. +
          2. Set requestURL’s query to the empty string.
          -
        4. -
        5. If matchFailed is false, then: +
        6. Set serializedCachedURL to serialized cachedURL. +
        7. Set serializedRequestURL to serialized requestURL. +
        8. + If serializedCachedURL matches serializedRequestURL, then:
            -
          1. Add an array [cachedRequest, cachedResponse] to resultArray.
          2. +
          3. Add record[0] to requestArray. +
          4. Add record[1] to responseArray.
          -
        9. +
      -
    9. -
    10. Return resultArray.
    11. -
    - - - - -

    Batch Cache Operations

    - - -
    -
    Input
    -
    operations, an array of CacheBatchOperation dictionary objects
    -
    Output
    -
    q, a promise resolves with an array of Response objects.
    -
    -
      -
    1. Let p be a promise resolved with no value.
    2. -
    3. Let q be transforming p with onFulfilled.
    4. -
    5. Upon fulfillment of p with value v, perform the following substeps, onFulfilled, in parallel: -
        -
      1. Let itemsCopy be a new request to response map that is a copy of its context object's request to response map.
      2. -
      3. Let addedRecords be an empty array.
      4. -
      5. Try running the following substeps atomically: +
      6. + For each cachedResponse in responseArray with the index index: +
          +
        1. Let cachedRequest be the indexth element in requestArray. +
        2. + If cachedResponse’s response’s header list contains no header named `Vary`, or options.ignoreVary is true, then: +
            +
          1. Add an array [cachedRequest, cachedResponse] to resultArray. +
          2. Continue to the next iteration of the loop. +
          +
        3. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
        4. Let matchFailed be false. +
        5. + For each f in varyHeaders: +
            +
          1. + If f matches "*", or the result of running cachedRequest.headers object’s get(name) method with f as the argument does not match the result of running request.headers object’s get(name) method with f as the argument, then:
              -
            1. Let resultArray be an empty array.
            2. -
            3. For each operation in operations with the index index: -
                -
              1. If operation.type matches neither "delete" nor "put", then: -
                  -
                1. Throw a TypeError.
                2. -
                -
              2. -
              3. If operation.type matches "delete" and operation.response is not null, then: -
                  -
                1. Throw a TypeError.
                2. -
                -
              4. -
              5. If the result of running Query Cache algorithm passing operation.request, operation.options, and addedRecords as the arguments is not an empty array, then: -
                  -
                1. Throw an "InvalidStateError" exception.
                2. -
                -
              6. -
              7. Let requestResponseArray be the result of running Query Cache algorithm passing operation.request and operation.options as the arguments.
              8. -
              9. For each requestResponse in requestResponseArray: -
                  -
                1. If operation.type matches "delete", remove the corresponding fetching record from request to response map.
                2. -
                -
              10. -
              11. If operation.type matches "put", then: -
                  -
                1. If operation.response is null, then: -
                    -
                  1. Throw a TypeError.
                  2. -
                  -
                2. -
                3. Let r be operation.request's associated request.
                4. -
                5. If r's url's scheme is not one of "http" and "https", then: -
                    -
                  1. Throw a TypeError.
                  2. -
                  -
                6. -
                7. If r's method is not `GET`, then: -
                    -
                  1. Throw a TypeError.
                  2. -
                  -
                8. -
                9. If operation.options is not null, then: -
                    -
                  1. Throw a TypeError.
                  2. -
                  -
                10. -
                11. If there exists a corresponding fetching record fetchingRecord for operation.request and operation.response in request to response map, set fetchingRecord.[[value]] to operation.response.
                12. -
                13. Else, set a newly-created fetching record {[[key]]: operation.request, [[value]]: operation.response} to request to response map.
                14. -

                  The cache commit is allowed as long as the response's headers are available.

                  -
                15. Add an array [operation.request, operation.response] to addedRecords.
                16. -
                -
              12. -
              13. Add operation.response to resultArray.
              14. -
              -
            4. -
            5. Resolve q with resultArray.
            6. +
            7. Set matchFailed to true. +
            8. Break the loop.
            -
          2. -
          3. And then, if an exception was thrown, then: +
          +
        6. If matchFailed is false, add an array [cachedRequest, cachedResponse] to resultArray. +
        +
      7. Return resultArray. +
      +
    +
    +

    Batch Cache Operations

    +
    +
    Input +
    operations, an array of CacheBatchOperation dictionary objects +
    Output +
    promise, a promise resolves with an array of Response objects. +
    +
      +
    1. Let p be a promise resolved with no value. +
    2. + Return the result of transforming p with a fulfillment handler that performs the following substeps in parallel: +
        +
      1. Let itemsCopy be a new request to response map that is a copy of its context object’s request to response map. +
      2. Let addedRecords be an empty array. +
      3. + Try running the following substeps atomically: +
          +
        1. Let resultArray be an empty array. +
        2. + For each operation in operations with the index index:
            -
          1. Set the context object's request to response map to itemsCopy.
          2. -
          3. Reject q with the exception
          4. +
          5. If operation.type matches neither "delete" nor "put", throw a TypeError. +
          6. If operation.type matches "delete" and operation.response is not null, throw a TypeError. +
          7. If the result of running Query Cache algorithm passing operation.request, operation.options, and addedRecords as the arguments is not an empty array, throw an "InvalidStateError" exception. +
          8. Let requestResponseArray be the result of running Query Cache algorithm passing operation.request and operation.options as the arguments. +
          9. + For each requestResponse in requestResponseArray: +
              +
            1. If operation.type matches "delete", remove the corresponding fetching record from request to response map. +
            +
          10. + If operation.type matches "put", then: +
              +
            1. If operation.response is null, throw a TypeError. +
            2. Let r be operation.request's associated request. +
            3. If r’s url’s scheme is not one of "http" and "https", throw a TypeError. +
            4. If r’s method is not `GET`, throw a TypeError. +
            5. If operation.options is not null, throw a TypeError. +
            6. If there exists a corresponding fetching record fetchingRecord for operation.request and operation.response in request to response map, set fetchingRecord.[[value]] to operation.response. +
            7. + Else, set a newly-created fetching record {[[key]]: operation.request, [[value]]: operation.response} to request to response map. +

              The cache commit is allowed as long as the response’s headers are available.

              +
            8. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "QuotaExceededError" exception. +
            9. Add an array [operation.request, operation.response] to addedRecords. +
            +
          11. Add operation.response to resultArray.
          -
        3. +
        4. Return resultArray. +
        +
      4. + And then, if an exception was thrown, then: +
          +
        1. Set the context object’s request to response map to itemsCopy. +
        2. Throw the exception +
      -
    3. -
    4. Return q.
    5. -
    - - + +
    +
    +
    +

    Appendix B: Extended HTTP headers

    +
    +

    Service Worker Script Request

    +

    An HTTP request to fetch a service worker’s script resource will include the following header:

    +
    +
    `Service-Worker` +
    + Indicates this request is a service worker’s script resource request. +

    This header helps administrators log the requests and detect threats.

    +
    +
    +
    +

    Service Worker Script Response

    +

    An HTTP response to a service worker’s script resource request can include the following header:

    +
    +
    `Service-Worker-Allowed` +
    + Indicates the user agent will override the path restriction, which limits the maximum allowed scope url that the script can control, to the given value. +

    The value is a URL. If a relative URL is given, it is parsed against the script’s URL.

    +
    +
    + Default scope: +
    // Maximum allowed scope defaults to the path the script sits in
    +// "/js" in this example
    +navigator.serviceWorker.register("/js/sw.js").then(function() {
    +  console.log("Install succeeded with the default scope '/js'.");
    +});
    +
    +
    + Upper path without Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response has no Service-Worker-Allowed header
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed due to the path restriction violation.");
    +});
    +
    +
    + Upper path with Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /"
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(function() {
    +  console.log("Install succeeded as the max allowed scope was overriden to '/'.");
    +});
    +
    +
    + A path restriction voliation even with Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /foo"
    +navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
    +});
    +
    +
    +
    +

    Syntax

    +

    ABNF for the values of the headers used by the service worker’s script resource requests and responses:

    +
    Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
    +
    +

    The validation of the Service-Worker-Allowed header’s values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.

    +
    +
    +
    +

    9. Acknowledgements

    +

    Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day’s discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

    +

    Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson’s rigorous Web Worker spec. Much thanks to him.

    +

    In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref and Jinho Bang.

    +

    Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

    +

    The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

    +

    Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.

    +
    +
    +
    +
    +

    Conformance

    +

    Document conventions

    +

    Conformance requirements are expressed with a combination of + descriptive assertions and RFC 2119 terminology. The key words “MUST”, + “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, + “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this + document are to be interpreted as described in RFC 2119. + However, for readability, these words do not appear in all uppercase + letters in this specification.

    +

    All of the text of this specification is normative except sections + explicitly marked as non-normative, examples, and notes. [RFC2119]

    +

    Examples in this specification are introduced with the words “for example” + or are set apart from the normative text with class="example", + like this:

    +
    + +

    This is an example of an informative example.

    +
    +

    Informative notes begin with the word “Note” and are set apart from the + normative text with class="note", like this:

    +

    Note, this is an informative note.

    +

    Conformant Algorithms

    +

    Requirements phrased in the imperative as part of algorithms (such as + "strip any leading space characters" or "return false and abort these + steps") are to be interpreted with the meaning of the key word ("must", + "should", "may", etc) used in introducing the algorithm.

    +

    Conformance requirements phrased as algorithms or specific steps can be + implemented in any manner, so long as the end result is equivalent#dfn-processing-equivalenceReferenced in:3.1.3. postMessage(message, transfer)3.2.1. installing3.2.2. waiting3.2.3. active3.2.5. update()3.2.6. unregister()3.4.1. controller3.4.2. ready (2)3.4.3. register(scriptURL, options)3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()4.1.3. skipWaiting() (2)4.2.4. postMessage(message, transfer)4.2.7. focus() (2)4.2.8. navigate(url) (2)4.3.1. get(id) (2) (3)4.3.2. matchAll(options) (2) (3) (4) (5)4.3.3. openWindow(url) (2)4.3.4. claim()4.4.1. event.waitUntil(f) (2)4.5.1. event.registerForeignFetch(options)4.6.4. event.respondWith(r)4.7.2. event.respondWith(r)5.4.1. match(request, options)5.4.2. matchAll(request, options)5.4.3. add(request)5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)5.4.7. keys(request, options)5.5.1. match(request, options)5.5.2. has(cacheName)5.5.3. open(cacheName)5.5.4. delete(cacheName)5.5.5. keys()8.4. Request Functional Event DispatchRegisterUpdateInstall (2)Handle Fetch (2) (3) (4)Handle Functional EventHandle Service Worker Client Unload (2). In + particular, the algorithms defined in this specification are intended to + be easy to understand and are not intended to be performant. Implementers + are encouraged to optimize.

    +
    + +

    Index

    +

    Terms defined by this specification

    + +

    Terms defined by reference

    + +

    References

    +

    Normative References

    +
    +
    [CSP2] +
    Mike West; Adam Barth; Daniel Veditz. Content Security Policy Level 2. 21 July 2015. CR. URL: https://w3c.github.io/webappsec/specs/CSP2/ +
    [ECMASCRIPT] +
    ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/ +
    [FETCH] +
    Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/ +
    [HTML] +
    Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/ +
    [PAGE-VISIBILITY] +
    Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: http://www.w3.org/TR/page-visibility/ +
    [POWERFUL-FEATURES] +
    Mike West; Yan Zhu. Privileged Contexts. 24 April 2015. WD. URL: https://w3c.github.io/webappsec/specs/powerfulfeatures/ +
    [PROMISES-GUIDE] +
    Writing Promise-Using Specifications. 24 July 2015. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/promises-guide +
    [QUOTA-API] +
    Kinuko Yasuda. Quota Management API. 15 December 2015. WD. URL: https://w3c.github.io/quota-api/ +
    [RFC2119] +
    S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119 +
    [RFC5234] +
    D. Crocker, Ed.; P. Overell. Augmented BNF for Syntax Specifications: ABNF. January 2008. Internet Standard. URL: https://tools.ietf.org/html/rfc5234 +
    [RFC7230] +
    R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing. June 2014. Proposed Standard. URL: https://tools.ietf.org/html/rfc7230 +
    [RFC7231] +
    R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content. June 2014. Proposed Standard. URL: https://tools.ietf.org/html/rfc7231 +
    [WebIDL-1] +
    Cameron McCormack; Boris Zbarsky. WebIDL Level 1. 8 March 2016. CR. URL: https://heycam.github.io/webidl/ +
    [WHATWG-DOM] +
    Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/ +
    [WHATWG-URL] +
    Anne van Kesteren; Sam Ruby. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/ +
    +

    Informative References

    +
    +
    [NOTIFICATIONS] +
    Anne van Kesteren. Notifications API Standard. Living Standard. URL: https://notifications.spec.whatwg.org/ +
    [UNSANCTIONED-TRACKING] +
    Unsanctioned Web Tracking. 17 July 2015. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/unsanctioned-tracking +
    +

    IDL Index

    +
    [Exposed=(Window,Worker)]
    +interface ServiceWorker : EventTarget {
    +  readonly attribute USVString scriptURL;
    +  readonly attribute ServiceWorkerState state;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +
    +  // event
    +  attribute EventHandler onstatechange;
    +};
    +ServiceWorker implements AbstractWorker;
    +
    +enum ServiceWorkerState {
    +  "installing",
    +  "installed",
    +  "activating",
    +  "activated",
    +  "redundant"
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface ServiceWorkerRegistration : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? installing;
    +  [Unforgeable] readonly attribute ServiceWorker? waiting;
    +  [Unforgeable] readonly attribute ServiceWorker? active;
    +
    +  readonly attribute USVString scope;
    +
    +  [NewObject] Promise<void> update();
    +  [NewObject] Promise<boolean> unregister();
    +
    +  // event
    +  attribute EventHandler onupdatefound;
    +};
    +
    +partial interface Navigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +partial interface WorkerNavigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface ServiceWorkerContainer : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? controller;
    +  [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
    +
    +  [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
    +
    +  [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
    +  [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
    +
    +
    +  // events
    +  attribute EventHandler oncontrollerchange;
    +  attribute EventHandler onerror;
    +  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
    +};
    +
    +dictionary RegistrationOptions {
    +  USVString scope;
    +  WorkerType type = "classic";
    +};
    +
    +[Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
    +interface ServiceWorkerMessageEvent : Event {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +dictionary ServiceWorkerMessageEventInit : EventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +[Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
    +interface ServiceWorkerGlobalScope : WorkerGlobalScope {
    +  // A container for a list of Client objects that correspond to
    +  // browsing contexts (or shared workers) that are on the origin of this SW
    +  [SameObject] readonly attribute Clients clients;
    +  [SameObject] readonly attribute ServiceWorkerRegistration registration;
    +
    +  [NewObject] Promise<void> skipWaiting();
    +
    +  attribute EventHandler oninstall;
    +  attribute EventHandler onactivate;
    +  attribute EventHandler onfetch;
    +  attribute EventHandler onforeignfetch;
    +
    +  // event
    +  attribute EventHandler onmessage; // event.source of the message events is Client object
    +
    +  // close() method inherited from WorkerGlobalScope should not be accessible.
    +};
    +
    +[Exposed=ServiceWorker]
    +interface Client {
    +  readonly attribute USVString url;
    +  readonly attribute FrameType frameType;
    +  readonly attribute DOMString id;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +};
    +
    +[Exposed=ServiceWorker]
    +interface WindowClient : Client {
    +  readonly attribute VisibilityState visibilityState;
    +  readonly attribute boolean focused;
    +  [NewObject] Promise<WindowClient> focus();
    +  [NewObject] Promise<WindowClient> navigate(USVString url);
    +};
    +
    +enum FrameType {
    +  "auxiliary",
    +  "top-level",
    +  "nested",
    +  "none"
    +};
    +
    +[Exposed=ServiceWorker]
    +interface Clients {
    +  // The objects returned will be new instances every time
    +  [NewObject] Promise<any> get(DOMString id);
    +  [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
    +  [NewObject] Promise<WindowClient?> openWindow(USVString url);
    +  [NewObject] Promise<void> claim();
    +};
    +
    +dictionary ClientQueryOptions {
    +  boolean includeUncontrolled = false;
    +  ClientType type = "window";
    +};
    +
    +enum ClientType {
    +  "window",
    +  "worker",
    +  "sharedworker",
    +  "all"
    +};
    +
    +[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableEvent : Event {
    +  void waitUntil(Promise<any> f);
    +};
     
    -
    +dictionary ExtendableEventInit : EventInit {
    +  // Defined for the forward compatibility across the derived events
    +};
    +
    +[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface InstallEvent : ExtendableEvent {
    +  void registerForeignFetch(ForeignFetchOptions options);
    +};
    +
    +dictionary ForeignFetchOptions {
    +  required sequence<USVString> scopes;
    +  required sequence<USVString> origins;
    +};
    +
    +[Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface FetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +  readonly attribute DOMString? clientId;
    +  readonly attribute boolean isReload;
    +
    +  void respondWith(Promise<Response> r);
    +};
    +
    +dictionary FetchEventInit : ExtendableEventInit {
    +  required Request request;
    +  DOMString? clientId = null;
    +  boolean isReload = false;
    +};
    +
    +[Constructor(DOMString type, ForeignFetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ForeignFetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +
    +  void respondWith(Promise<ForeignFetchResponse> r);
    +};
     
    -
    -  

    Acknowledgements

    - +dictionary ForeignFetchEventInit : ExtendableEventInit { + required Request request; +}; + +dictionary ForeignFetchResponse { + required Response response; + USVString origin; + sequence<ByteString> headers; +}; + +[Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker] +interface ExtendableMessageEvent : ExtendableEvent { + readonly attribute any data; + readonly attribute DOMString origin; + readonly attribute DOMString lastEventId; + [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source; + [SameObject] readonly attribute MessagePort[]? ports; +}; + +dictionary ExtendableMessageEventInit : ExtendableEventInit { + any data; + DOMString origin; + DOMString lastEventId; + (Client or ServiceWorker or MessagePort)? source; + sequence<MessagePort>? ports; +}; -

    Jake Archibald is a ghost-author of this document. The best instincts in the design are his. He similarly shaped many of the details through discussion and experimentation. The bits which are not his (but which are good) owe everything to his experience, persistence, and focus on enabling web developers. He embodies a hopeful example for developers in shaping browser efforts to more directly address real-world pain points. If service workers solve "offline for the web", the credit is due him.

    +partial interface Window { + [SameObject] readonly attribute CacheStorage caches; +}; -

    Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

    +partial interface WorkerGlobalScope { + [SameObject] readonly attribute CacheStorage caches; +}; -

    Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.

    +[Exposed=(Window,Worker)] +interface Cache { + [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options); + [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options); + [NewObject] Promise<void> add(RequestInfo request); + [NewObject] Promise<void> addAll(sequence<RequestInfo> requests); + [NewObject] Promise<void> put(RequestInfo request, Response response); + [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options); + [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options); +}; -

    In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, and Ben Kelly.

    +dictionary CacheQueryOptions { + boolean ignoreSearch = false; + boolean ignoreMethod = false; + boolean ignoreVary = false; + DOMString cacheName; +}; -

    Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

    +dictionary CacheBatchOperation { + DOMString type; + Request request; + Response response; + CacheQueryOptions options; +}; -

    The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

    +[Exposed=(Window,Worker)] +interface CacheStorage { + [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options); + [NewObject] Promise<boolean> has(DOMString cacheName); + [NewObject] Promise<Cache> open(DOMString cacheName); + [NewObject] Promise<boolean> delete(DOMString cacheName); + [NewObject] Promise<sequence<DOMString>> keys(); +}; -

    Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, and Wonsuk Lee for their considerable professional support.

    -
    - - +
    +

    Issues Index

    +
    +
    The behavior of the attribute getter in non-secure contexts is in discussion.
    +
    These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.
    +
    These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.
    +
    Remove this definition after sorting out the referencing sites.
    +
    This needs an extra step in the HTTP fetch algorithm in between step 3 and 4, to call this algorithm for all requests if response is null at that point.
    +
    + \ No newline at end of file diff --git a/spec/service_worker/sw-registration-figure.svg b/spec/service_worker/sw-registration-figure.svg new file mode 100644 index 00000000..6dc1b4c3 --- /dev/null +++ b/spec/service_worker/sw-registration-figure.svg @@ -0,0 +1 @@ +RegisterUpdateInstallActivatenavigator.serviceWorker.register()registration.update()Soft Updatefetchscript matchregistrationCreateUnregisterDeleteactivewaitinginstalling^^^Handle Service Worker Client Unloadon errorwhen uninstalling flag is setregistration.unregister()PushManagerSyncManagerGeofenceManagerServiceWorkerRegistrationClear Registrationon error \ No newline at end of file diff --git a/spec/service_worker_1/index.bs b/spec/service_worker_1/index.bs new file mode 100644 index 00000000..27510792 --- /dev/null +++ b/spec/service_worker_1/index.bs @@ -0,0 +1,3953 @@ + + +
    +{
    +  "promises-guide": {
    +    "href": "https://www.w3.org/2001/tag/doc/promises-guide",
    +    "title": "Writing Promise-Using Specifications",
    +    "date": "24 July 2015",
    +    "status": "Finding of the W3C TAG",
    +    "publisher": "W3C TAG"
    +  },
    +  "unsanctioned-tracking": {
    +    "href": "https://www.w3.org/2001/tag/doc/unsanctioned-tracking",
    +    "title": "Unsanctioned Web Tracking",
    +    "date": "17 July 2015",
    +    "status": "Finding of the W3C TAG",
    +    "publisher": "W3C TAG"
    +  }
    +}
    +
    + + + +
    +spec: dom-ls; urlPrefix: https://dom.spec.whatwg.org/
    +    type: dfn; text: ASCII case-insensitive; url: ascii-case-insensitive
    +
    +spec: ecma-262; urlPrefix: http://www.ecma-international.org/ecma-262/6.0/
    +    type: dfn
    +        text: Assert; url: sec-algorithm-conventions
    +        text: [[Call]]; url: sec-ecmascript-function-objects-call-thisargument-argumentslist
    +        text: map objects; url: sec-map-objects
    +        text: promise; url: sec-promise-objects
    +        url: sec-list-and-record-specification-type
    +            text: List
    +            text: Record
    +
    +spec: csp2; urlPrefix: https://w3c.github.io/webappsec-csp/2/
    +    type: dfn
    +        text: enforce
    +        text: monitor
    +
    +spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
    +    type: dfn
    +        text: basic filtered response; url: concept-filtered-response-basic
    +        text: CORS filtered response; url: concept-filtered-response-cors
    +        text: disturbed; url: concept-body-disturbed
    +        text: empty; url: concept-empty-readablestream
    +        text: extract a mime type; url: concept-header-extract-mime-type
    +        text: fetch; url: concept-fetch
    +        text: filtered response; url: concept-filtered-response
    +        text: get a reader; url: concept-get-reader
    +        text: header; url: concept-header
    +        text: internal response; url: concept-internal-response
    +        text: http fetch; url: concept-http-fetch
    +        text: locked; url: concept-body-locked
    +        text: navigation request
    +        text: network error; url: concept-network-error
    +        text: non-subresource request
    +        text: ok status; url: ok-status
    +        text: opaque filtered response; url: concept-filtered-response-opaque
    +        text: potential-navigation-or-subresource request
    +        text: process response
    +        text: process response end-of-file
    +        text: read all bytes; url: concept-read-all-bytes-from-readablestream
    +        text: ReadableStream; url: concept-readablestream
    +        text: request; for: fetch; url: concept-request
    +        text: response; for: fetch; url: concept-response
    +        text: skip service worker flag
    +        text: stream; url: concept-body-stream
    +        text: subresource request
    +        text: synchronous flag
    +        text: terminate; url: concept-fetch-terminate
    +        text: guard; for: headers; url: concept-headers-guard
    +        for: header; urlPrefix: #concept-header-
    +            text: name
    +            text: parsing; url: parse
    +        for: request; urlPrefix: #concept-request-
    +            text: cache mode
    +            text: client
    +            text: destination
    +            text: header list
    +            text: initiator
    +            text: method
    +            text: redirect mode
    +            text: request
    +            text: url
    +        for: response; urlPrefix: #concept-response-
    +            text: body
    +            text: cache state
    +            text: header list
    +            text: response
    +            text: status
    +            text: termination reason
    +            text: type
    +    type: interface
    +        text: Headers
    +        text: Request
    +        text: RequestInfo
    +        text: Response
    +    type: attribute; for: Request
    +        text: headers; url: dom-request-headers
    +    type: method
    +        text: get(name); for: Headers; url: dom-headers-get
    +        text: fetch(input, init); for: GlobalFetch; url: dom-global-fetch
    +
    +spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
    +    type: dfn
    +        urlPrefix: browsers.html
    +            text: origin; for: resource; url: origin-2
    +        urlPrefix: infrastructure.html
    +            text: read only array; url: dfn-read-only-array
    +        urlPrefix: interaction.html
    +            text: has focus steps
    +        urlPrefix: webappapis.html
    +            text: creation url
    +            text: dom manipulation task source
    +            text: fire a simple event
    +            text: report the error
    +            text: task queue; for: event loop
    +        urlPrefix: workers.html
    +            text: get a fetch result
    +            text: import scripts into worker global scope
    +            text: postprocess the fetch result
    +            text: runtime script errors handling; url: runtime-script-errors-2
    +            text: shared workers
    +            text: validate the state
    +            text: web worker; url: workers
    +    type: event
    +        urlPrefix: indices.html
    +            text: DOMContentLoaded; for: Document; url: event-domcontentloaded
    +            text: message; for: Window; url: event-message
    +
    +spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/
    +    type: enum; text: VisibilityState; url: VisibilityState
    +    type: attribute; text: visibilityState; for: Document; url: dom-document-visibilitystate
    +
    +spec: powerful-features; urlPrefix: https://w3c.github.io/webappsec/specs/powerfulfeatures/#
    +    type: dfn
    +        text: is origin potentially trustworthy; url: is-origin-trustworthy
    +        text: risks associated with insecure contexts; url: threat-risks
    +        text: secure context
    +
    +spec: promises-guide; urlPrefix: https://www.w3.org/2001/tag/doc/promises-guide#
    +    type: dfn
    +        text: waiting for all
    +        text: transforming; url: transforming-by
    +
    +spec: quota-api; urlPrefix: http://www.w3.org/TR/quota-api/
    +    type: attribute; for: ServiceWorkerGlobalScope
    +        text: onbeforeevicted; url: widl-ServiceWorkerGlobalScope-onbeforeevicted
    +        text: onevicted; url: widl-ServiceWorkerGlobalScope-onevicted
    +
    +spec: rfc7230; urlPrefix: https://tools.ietf.org/html/rfc7230
    +    type: dfn
    +        text: field-value; for: http; url: section-3.2
    +
    +spec: rfc7231; urlPrefix: https://tools.ietf.org/html/rfc7231
    +    type: dfn
    +        text: Vary; url: section-7.1.4
    +
    +spec: url; urlPrefix: https://url.spec.whatwg.org/
    +    type: dfn
    +        text: parsing; for: url; url: concept-url-parser
    +        text: serialized; for: url; url: concept-url-serializer
    +
    +spec: webidl; urlPrefix: https://heycam.github.io/webidl/
    +    type: dfn
    +        text: throw; url: dfn-throw
    +    type: exception
    +        text: DataCloneError
    +        text: InvalidAccessError
    +        text: InvalidStateError
    +        text: NetworkError
    +        text: NotFoundError
    +        text: QuotaExceededError
    +        text: SecurityError
    +
    + +
    +

    Motivations

    + + This section is non-normative. + +

    Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

    + +

    The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

    + +

    Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

    + +

    Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

    + +

    Service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

    + +

    Service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

    +
    + +
    +

    Model

    + +
    +

    Service Worker

    + +

    A service worker is a type of web worker. A service worker executes in the registering service worker client's origin.

    +

    A service worker has an associated state, which is one of parsed, installing, installed, activating, activated, and redundant. It is initially parsed.

    +

    A service worker has an associated script url (a URL).

    +

    A service worker has an associated containing service worker registration (a service worker registration), which contains itself.

    +

    A service worker has an associated id (an opaque string), which uniquely identifies itself during the lifetime of its containing service worker registration.

    +

    A service worker is dispatched a set of lifecycle events, install and activate, and functional events including fetch.

    +

    A service worker has an associated script resource, which represents its own script resource. It is initially set to null. A script resource has an associated has ever been evaluated flag. It is initially unset.

    +

    A service worker has an associated script resource map which is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a URL and \[[value]] is a script resource.

    +

    A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.

    +

    A service worker has an associated imported scripts updated flag. It is initially unset.

    +

    A service worker has an associated set of event types to handle whose element type is an event listener's event type. It is initially set to null.

    + +
    +

    Lifetime

    + +

    The lifetime of a service worker is tied to the execution lifetime of events and not references held by service worker clients to the ServiceWorker object.

    +

    A user agent may terminate service workers at any time it:

    +
      +
    • Has no event to handle.
    • +
    • Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events.
    • +
    +
    +
    + +
    +

    Service Worker Registration

    + +

    A service worker registration is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. A user agent may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

    +

    A service worker registration has an associated scope url (a URL).

    +

    A service worker registration has an associated registering script url (a URL).

    +

    A service worker registration has an associated installing worker (a service worker) whose state is installing. It is initially set to null.

    +

    A service worker registration has an associated waiting worker (a service worker) whose state is installed. It is initially set to null.

    +

    A service worker registration has an associated active worker (a service worker) whose state is either activating or activated. It is initially set to null.

    +

    A service worker registration has an associated last update check time. It is initially set to null.

    +

    A service worker registration has an associated uninstalling flag. It is initially unset.

    +

    A service worker registration has one or more task queues that back up the tasks from its active worker's event loop's corresponding task queues. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker's tasks to the service worker registration's task queues when the active worker is terminated and re-queues those tasks to the active worker's event loop's corresponding task queues when the active worker spins off. Unlike the task queues owned by event loops, the service worker registration's task queues are not processed by any event loops in and of itself.

    + +
    +

    Lifetime

    + +

    A user agent must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of service worker registration's scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

    +
    +
    + +
    +

    Service Worker Client

    +

    A service worker client is an environment settings object that specifies various settings for its JavaScript global environment.

    + +

    A service worker client has an associated active worker (an active worker) which currently controls it. It is initially set to null.

    + +

    A service worker client has an associated id (an opaque string), which uniquely identifies itself during its lifetime. It is initially set to a new unique value when the corresponding environment settings object that it represents is created.

    + +

    A service worker client has an associated frame type, which is one of auxiliary, top-level, nested, and none. Unless stated otherwise it is none. + +

    A window client is a service worker client whose global object is a {{Window}} object.

    + +

    A dedicated worker client is a service worker client whose global object is a {{DedicatedWorkerGlobalScope}} object.

    + +

    A shared worker client is a service worker client whose global object is a {{SharedWorkerGlobalScope}} object.

    + +

    A worker client is either a dedicated worker client or a shared worker client.

    +
    + +
    +

    Selection and Use

    + +

    A service worker client independently selects and uses a service worker registration for its own loading and its subresources. The selection of a service worker registration, upon a non-subresource request, is a process of either matching a service worker registration from scope to registration map or inheriting an existing service worker registration from its parent or owner context depending on the request's url.

    + +

    When the request's url is not local, a service worker client matches a service worker registration from scope to registration map. That is, the service worker client attempts to consult a service worker registration whose scope url matches its creation url.

    + +

    When the request's url is local, if the service worker client's responsible browsing context is a nested browsing context or the service worker client is a worker client, the service worker client inherits the service worker registration from its parent browsing context's environment or one of the worker's Documents' environment, respectively, if it exists.

    + +

    If the selection was successful, the selected service worker registration's active worker starts to control the service worker client. Otherwise, the flow returns to fetch where it falls back to the default behavior. When a service worker client is controlled by an active worker, it is considered that the service worker client is using the active worker's containing service worker registration.

    +
    + +
    +

    Task sources

    + +

    The following additional task sources are used by service workers.

    + +
    +
    The handle fetch task source
    +
    This task source is used for dispatching fetch events to service workers.
    +
    The handle functional event task source
    +
    This task source is used for features that dispatch other functional events, e.g. push events, to service workers. +

    A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. For instance, a user agent may use a different task source for task events from other task sources.

    +
    +
    +
    + +
    +

    User Agent Shutdown

    + +

    A user agent must maintain the state of its stored service worker registrations across restarts with the following rules: +

    +

    + +

    To attain this, the user agent must invoke Handle User Agent Shutdown when it terminates.

    +
    +
    + +
    +

    Client Context

    + +
    + Bootstrapping with a ServiceWorker: + +
    +      // scope defaults to the path the script sits in
    +      // "/" in this example
    +      navigator.serviceWorker.register("/serviceworker.js").then(
    +        function(registration) {
    +          console.log("success!");
    +          if (registration.installing) {
    +            registration.installing.postMessage("Howdy from your installing page.");
    +          }
    +        },
    +        function(why) {
    +          console.error("Installing the worker failed!:", why);
    +        });
    +    
    +
    + +
    +

    {{ServiceWorker}}

    + +
    +      [Exposed=(Window,Worker)]
    +      interface ServiceWorker : EventTarget {
    +        readonly attribute USVString scriptURL;
    +        readonly attribute ServiceWorkerState state;
    +        void postMessage(any message, optional sequence<Transferable> transfer);
    +
    +        // event
    +        attribute EventHandler onstatechange;
    +      };
    +      ServiceWorker implements AbstractWorker;
    +
    +      enum ServiceWorkerState {
    +        "installing",
    +        "installed",
    +        "activating",
    +        "activated",
    +        "redundant"
    +      };
    +    
    + +

    A ServiceWorker object represents a service worker. Each {{ServiceWorker}} object is associated with a service worker. Multiple separate objects implementing the {{ServiceWorker}} interface across document environments and worker environments can all be associated with the same service worker simultaneously.

    + +

    A {{ServiceWorker}} object has an associated {{ServiceWorkerState}} object which is itself associated with service worker's state.

    + +
    +

    {{ServiceWorker/scriptURL}}

    + +

    The scriptURL attribute must return the service worker's serialized script url.

    + +
    +

    For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

    + +
    +          // Script on the page https://example.com/app.html
    +          navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
    +        
    + +

    The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

    +
    +
    + +
    +

    {{ServiceWorker/state}}

    + +

    The state attribute must return the value (in ServiceWorkerState enumeration) corresponding to the first matching statement, switching on the service worker's state:

    + +
    +
    installing
    +
    "installing" +

    The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

    + +
    installed
    +
    "installed" +

    The service worker in this state is considered a waiting worker.

    + +
    activating
    +
    "activating" +

    The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

    + +
    activated
    +
    "activated" +

    The service worker in this state is considered an active worker ready to handle functional events.

    + +
    redundant
    +
    "redundant" +

    A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

    +
    +
    + +
    +

    {{ServiceWorker/postMessage(message, transfer)}}

    + +

    The postMessage(message, transfer) method must run these steps or their equivalent:

    + +
      +
    1. If the {{ServiceWorker/state}} attribute value of the context object is "redundant", throw an "{{InvalidStateError}}" exception and abort these steps.
    2. +
    3. Let newPorts be an empty array.
    4. +
    5. Let transferMap be an empty association list of {{Transferable}} objects to placeholder objects.
    6. +
    7. If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. If any object is listed in transfer more than once, or any of the {{Transferable}} objects listed in transfer are marked as neutered, then throw a "{{DataCloneError}}" exception and abort these steps.
      2. +
      3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a {{MessagePort}} object, also append the placeholder object to newPorts.
      4. +
      +
    8. +
    9. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
    10. +
    11. Let serviceWorker be the service worker represented by the context object.
    12. +
    13. Invoke Run Service Worker algorithm with serviceWorker as the argument.
    14. +
    15. Let destination be the {{ServiceWorkerGlobalScope}} object associated with serviceWorker.
    16. +
    17. If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. Let newOwner be the destination's environment settings object.
      2. +
      3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
      4. +
      +
    18. +
    19. Make newPorts into a read only array.
    20. +
    21. Queue a task that runs the following steps: +
        +
      1. Create an event e that uses the {{ExtendableMessageEvent}} interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
      2. +
      3. Let the {{ExtendableMessageEvent/data}} attribute of e be initialized to clonedMessage.
      4. +
      5. Let the {{ExtendableMessageEvent/origin}} attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
      6. +
      7. If the global object globalObject specified by the incumbent settings object is a {{ServiceWorkerGlobalScope}} object, let the {{ExtendableMessageEvent/source}} attribute of e be initialized to a new {{ServiceWorker}} object that represents globalObject's service worker.
      8. +
      9. Else if globalObject is a {{Window}} object, let the {{ExtendableMessageEvent/source}} attribute of e be initialized to a new {{WindowClient}} object that represents globalObject's browsing context.
      10. +
      11. Else, let it be initialized to a new {{Client}} object that represents globalObject's worker environment.
      12. +
      13. Let the {{ExtendableMessageEvent/ports}} attribute of e be initialized to newPorts.
      14. +
      15. Dispatch e at destination.
      16. +
      +

      The task must use the DOM manipulation task source.

      +
    22. +
    +
    + +
    +

    Event handler

    + +

    The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorker}} interface:

    + + + + + + + + + + + + + + +
    event handlerevent handler event type
    onstatechangestatechange
    +
    +
    + +
    +

    {{ServiceWorkerRegistration}}

    + +
    +      [Exposed=(Window,Worker)]
    +      interface ServiceWorkerRegistration : EventTarget {
    +        [Unforgeable] readonly attribute ServiceWorker? installing;
    +        [Unforgeable] readonly attribute ServiceWorker? waiting;
    +        [Unforgeable] readonly attribute ServiceWorker? active;
    +
    +        readonly attribute USVString scope;
    +
    +        [NewObject] Promise<void> update();
    +        [NewObject] Promise<boolean> unregister();
    +
    +        // event
    +        attribute EventHandler onupdatefound;
    +      };
    +    
    + +

    A ServiceWorkerRegistration object represents a service worker registration. Each {{ServiceWorkerRegistration}} object is associated with a service worker registration (a service worker registration). Multiple separate objects implementing the {{ServiceWorkerRegistration}} interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

    + +
    + + +

    installing attribute must return the result of running these steps or their equivalent:

    + +
      +
    1. Let installingWorker be the {{ServiceWorker}} object that represents the service worker registration's installing worker.
    2. +
    3. Return installingWorker.
    4. +
    + +

    The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    + +
    + + +

    waiting attribute must return the result of running these steps or their equivalent:

    + +
      +
    1. Let waitingWorker be the {{ServiceWorker}} object that represents the service worker registration's waiting worker.
    2. +
    3. Return waitingWorker.
    4. +
    + +

    The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    + +
    + + +

    active attribute must return the result of running these steps or their equivalent:

    + +
      +
    1. Let activeWorker be the {{ServiceWorker}} object that represents the service worker registration's active worker.
    2. +
    3. Return activeWorker.
    4. +
    + +

    The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    + +
    +

    {{ServiceWorkerRegistration/scope}}

    + +

    The scope attribute must return service worker registration's serialized scope url.

    + +

    In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

    +
    + +
    +

    {{ServiceWorkerRegistration/update()}}

    + +

    update() method must run these steps or their equivalent:

    + +
      +
    1. Let p be a promise.
    2. +
    3. Let registration be the service worker registration.
    4. +
    5. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
    6. +
    7. If newestWorker is null, reject p with an "{{InvalidStateError}}" exception and abort these steps.
    8. +
    9. If the context object's relevant settings object's global object globalObject is a {{ServiceWorkerGlobalScope}} object, and globalObject's associated service worker's state is installing, reject p with an "{{InvalidStateError}}" exception and abort these steps.
    10. +
    11. Let job be the result of running Create Job with update, registration's scope url, newestWorker's script url, p, and the context object's relevant settings object client.
    12. +
    13. Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job.
      2. +
      +
    14. +
    15. Return p.
    16. +
    +
    + +
    + + +

    The {{ServiceWorkerRegistration/unregister()}} method unregisters the service worker registration. It is important to note that the currently controlled service worker client's active worker's containing service worker registration is effective until all the service worker clients (including itself) using this service worker registration unload. That is, the {{ServiceWorkerRegistration/unregister()}} method only affects subsequent navigations.

    + +

    unregister() method must return the result of running these steps or their equivalent:

    + +
      +
    1. Let p be a promise.
    2. +
    3. Let job be the result of running Create Job with unregister, the scope url of the service worker registration, null, p, and the context object's relevant settings object client.
    4. +
    5. Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job.
      2. +
      +
    6. +
    7. Return p.
    8. +
    +
    + +
    +

    Event handler

    + +

    The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

    + + + + + + + + + + + + + + +
    event handlerevent handler event type
    onupdatefoundupdatefound
    +
    +
    + +
    + + +
    +      partial interface Navigator {
    +        [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +      };
    +
    +      partial interface WorkerNavigator {
    +        [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +      };
    +    
    + +

    The serviceWorker attribute must return the {{ServiceWorkerContainer}} object that is associated with the context object.

    +
    + +
    +

    {{ServiceWorkerContainer}}

    + +
    +      [Exposed=(Window,Worker)]
    +      interface ServiceWorkerContainer : EventTarget {
    +        [Unforgeable] readonly attribute ServiceWorker? controller;
    +        [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
    +
    +        [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
    +
    +        [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
    +        [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
    +
    +
    +        // events
    +        attribute EventHandler oncontrollerchange;
    +        attribute EventHandler onerror;
    +        attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
    +      };
    +    
    +
    +      dictionary RegistrationOptions {
    +        USVString scope;
    +      };
    +    
    + +

    The user agent must create a {{ServiceWorkerContainer}} object when a {{Navigator}} object or a {{WorkerNavigator}} object is created and associate it with that object.

    + +

    A ServiceWorkerContainer provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

    + +

    A {{ServiceWorkerContainer}} has an associated service worker client, which is a service worker client whose global object is associated with the {{Navigator}} object or the {{WorkerNavigator}} object that the {{ServiceWorkerContainer}} is retrieved from.

    + +

    A {{ServiceWorkerContainer}} object has an associated ready promise (a promise). It is initially set to a new promise.

    + +
    + + +

    controller attribute must return the result of running these steps or their equivalent:

    + +
      +
    1. Let client be the context object's service worker client.
    2. +
    3. If client is not a secure context, return undefined.
    4. +
    5. Return the {{ServiceWorker}} object that represents client's active worker.
    6. +
    + +

    {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} returns null if the request is a force refresh (shift+refresh). The {{ServiceWorker}} objects returned from this attribute getter that represent the same service worker are the same objects.

    + +

    The behavior of the attribute getter in non-secure contexts is in discussion.

    +
    + +
    + + +

    ready attribute must return the result of running these steps or their equivalent:

    + +
      +
    1. If the context object's ready promise is settled, return the context object's ready promise.
    2. +
    3. Let client be the context object's service worker client.
    4. +
    5. If client is not a secure context, return the context object's ready promise rejected with a "{{SecurityError}}" exception.
    6. +
    7. Let registration be null.
    8. +
    9. Let clientURL be client's creation url.
    10. +
    11. Run the following substeps in parallel: +
        +
      1. CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
          +
        1. Set registration to the result value.
        2. +
        +
      2. +
      3. Else: +
          +
        1. Wait until scope to registration map has a new entry.
        2. +
        3. Jump to the step labeled CheckRegistration.
        4. +
        +
      4. +
      5. If registration's active worker is null, wait until registration's active worker changes. +

        Implementers should consider this condition is met when the corresponding registration request gets to the step 7 of Activate algorithm.

        +
      6. +
      7. Resolve context object's ready promise with the {{ServiceWorkerRegistration}} object which represents registration.
      8. +
      +
    12. +
    13. Return context object's ready promise.
    14. +
    + +

    When the ready attribute is accessed in a secure context, the returned promise will never reject. Instead, it waits until the promise resolves with a service worker registration that has an active worker.

    +
    + +
    + + +

    The {{ServiceWorkerContainer/register(scriptURL, options)}} method creates or updates a service worker registration for the given scope url. If successful, a service worker registration ties the provided scriptURL to a scope url, which is subsequently used for navigation matching.

    + +

    register(scriptURL, options) method must run these steps or their equivalent:

    + +
      +
    1. Let p be a promise.
    2. +
    3. Let client be the context object's service worker client.
    4. +
    5. If client is not a secure context, reject p with a "{{SecurityError}}" exception and abort these steps.
    6. +
    7. Let scriptURL be the result of parsing scriptURL with entry settings object's API base URL.
    8. +
    9. If scriptURL is failure, reject p with a TypeError and abort these steps.
    10. +
    11. If scriptURL's scheme is not one of "http" and "https", reject p with a TypeError and abort these steps.
    12. +
    13. If any of the strings in scriptURL's path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps.
    14. +
    15. Let scopeURL be null.
    16. +
    17. If options.{{RegistrationOptions/scope}} is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

      The scope url for the registration is set to the location of the service worker script by default.

      +
    18. +
    19. Else, set scopeURL to the result of parsing options.{{RegistrationOptions/scope}} with entry settings object's API base URL.
    20. +
    21. If scopeURL is failure, reject p with a TypeError and abort these steps.
    22. +
    23. If scopeURL's scheme is not one of "http" and "https", reject p with a TypeError and abort these steps.
    24. +
    25. If any of the strings in scopeURL's path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps.
    26. +
    27. Let job be the result of running Create Job with register, scopeURL, scriptURL, p, and client.
    28. +
    29. Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job.
      2. +
      +
    30. +
    31. Return p.
    32. +
    +
    + +
    + + +

    getRegistration(clientURL) method must run these steps or their equivalent:

    + +
      +
    1. Let client be the context object's service worker client.
    2. +
    3. If client is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    4. +
    5. Let clientURL be the result of parsing clientURL with entry settings object's API base URL.
    6. +
    7. If clientURL is failure, return a promise rejected with a TypeError.
    8. +
    9. If the origin of clientURL is not client's origin, return a promise rejected with a "{{SecurityError}}" exception.
    10. +
    11. Let promise be a new promise.
    12. +
    13. Run the following substeps in parallel: +
        +
      1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument.
      2. +
      3. If registration is not null, then: +
          +
        1. Resolve promise with the {{ServiceWorkerRegistration}} object which represents registration.
        2. +
        +
      4. +
      5. Else: +
          +
        1. Resolve promise with undefined.
        2. +
        +
      6. +
      +
    14. +
    15. Return promise.
    16. +
    +
    + +
    + + +

    getRegistrations() method must run these steps or their equivalent:

    + +
      +
    1. Let client be the context object's service worker client.
    2. +
    3. If client is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    4. +
    5. Let promise be a new promise.
    6. +
    7. Run the following substeps in parallel: +
        +
      1. Let array be an empty array.
      2. +
      3. For each Record {\[[key]], \[[value]]} entry of scope to registration map: +
          +
        1. If the origin of the result of parsing entry.\[[key]] is the same as client's origin, add the {{ServiceWorkerRegistration}} object associated with entry.\[[value]] to the array.
        2. +
        +
      4. +
      5. Resolve promise with array.
      6. +
      +
    8. +
    9. Return promise.
    10. +
    +
    + +
    +

    Event handlers

    + +

    The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

    + + + + + + + + + + + + + + + + + + + + + + +
    event handlerevent handler event type
    oncontrollerchangecontrollerchange
    onerrorerror
    onmessagemessage
    +
    +
    + +
    +

    {{ServiceWorkerMessageEvent}}

    + +
    +      [Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
    +      interface ServiceWorkerMessageEvent : Event {
    +        readonly attribute any data;
    +        readonly attribute DOMString origin;
    +        readonly attribute DOMString lastEventId;
    +        [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
    +        [SameObject] readonly attribute MessagePort[]? ports;
    +      };
    +    
    +
    +      dictionary ServiceWorkerMessageEventInit : EventInit {
    +        any data;
    +        DOMString origin;
    +        DOMString lastEventId;
    +        (ServiceWorker or MessagePort)? source;
    +        sequence<MessagePort>? ports;
    +      };
    +    
    + +

    Service workers define the message event that extends the {{Window/message}} event defined in [[!HTML]] to allow setting a {{ServiceWorker}} object as the source of the message. For the message event, service workers use the ServiceWorkerMessageEvent interface.

    + +
    +

    {{ServiceWorkerMessageEvent/data|event.data}}

    + +

    The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    + +
    +

    {{ServiceWorkerMessageEvent/origin|event.origin}}

    + +

    The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker's environment settings object from which the message is sent.

    +
    + +
    +

    {{ServiceWorkerMessageEvent/lastEventId|event.lastEventId}}

    + +

    The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    + +
    +

    {{ServiceWorkerMessageEvent/source|event.source}}

    + +

    The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the ServiceWorker object whose associated service worker the message is sent from.

    +
    + +
    +

    {{ServiceWorkerMessageEvent/ports|event.ports}}

    + +

    The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{MessagePort}} array being sent, if any.

    +
    +
    + +
    +

    Events

    + +

    The following event is dispatched on {{ServiceWorker}} object:

    + + + + + + + + + + + + + + + + +
    Event nameInterfaceDispatched when…
    statechange{{Event}}The {{ServiceWorker/state}} attribute of the {{ServiceWorker}} object is changed.
    + +

    The following event is dispatched on {{ServiceWorkerRegistration}} object:

    + + + + + + + + + + + + + + + + +
    Event nameInterfaceDispatched when…
    updatefound{{Event}}The service worker registration's installing worker changes. (See step 7 of the Install algorithm.)
    + +

    The following events are dispatched on {{ServiceWorkerContainer}} object:

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Event nameInterfaceDispatched when…
    controllerchange{{Event}}The service worker client's active worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} immediately reflects the active worker as the service worker that controls the service worker client.)
    message{{ServiceWorkerMessageEvent}}When it receives a message.
    error{{ErrorEvent}}Any error occurred from the associated service workers.
    +
    +
    + +
    +

    Execution Context

    + +
    + Serving Cached Resources: + +
    +      // caching.js
    +      this.addEventListener("install", function(e) {
    +        e.waitUntil(
    +          // Open a cache of resources.
    +          caches.open("shell-v1").then(function(cache) {
    +            // Begins the process of fetching them.
    +            // The coast is only clear when all the resources are ready.
    +            return cache.addAll([
    +              "/app.html",
    +              "/assets/v1/base.css",
    +              "/assets/v1/app.js",
    +              "/assets/v1/logo.png",
    +              "/assets/v1/intro_video.webm"
    +            ]);
    +          })
    +        );
    +      });
    +
    +      this.addEventListener("fetch", function(e) {
    +        // No "fetch" events are dispatched to the service worker until it
    +        // successfully installs and activates.
    +
    +        // All operations on caches are async, including matching URLs, so we use
    +        // promises heavily. e.respondWith() even takes promises to enable this:
    +        e.respondWith(
    +          caches.match(e.request).then(function(response) {
    +            return response || fetch(e.request);
    +          }).catch(function() {
    +            return caches.match("/fallback.html");
    +          })
    +        );
    +      });
    +    
    +
    + +
    +

    {{ServiceWorkerGlobalScope}}

    + +
    +      [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
    +      interface ServiceWorkerGlobalScope : WorkerGlobalScope {
    +        // A container for a list of Client objects that correspond to
    +        // browsing contexts (or shared workers) that are on the origin of this SW
    +        [SameObject] readonly attribute Clients clients;
    +        [SameObject] readonly attribute ServiceWorkerRegistration registration;
    +
    +        [NewObject] Promise<void> skipWaiting();
    +
    +        attribute EventHandler oninstall;
    +        attribute EventHandler onactivate;
    +        attribute EventHandler onfetch;
    +
    +        // event
    +        attribute EventHandler onmessage; // event.source of the message events is Client object
    +
    +        // close() method inherited from WorkerGlobalScope should not be accessible.
    +      };
    +    
    + +

    A ServiceWorkerGlobalScope object represents the global execution context of a service worker. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a service worker).

    + +

    {{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

    + +

    The {{WorkerGlobalScope/close()}} method inherited from {{WorkerGlobalScope}}, when called on the context object, should throw an "{{InvalidAccessError}}" exception.

    + +
    +

    {{ServiceWorkerGlobalScope/clients}}

    + +

    clients attribute must return the {{Clients}} object that is associated with the context object.

    +
    + +
    +

    {{ServiceWorkerGlobalScope/registration}}

    + +

    The registration attribute must return the {{ServiceWorkerRegistration}} object that represents the service worker's containing service worker registration.

    +
    + +
    +

    {{ServiceWorkerGlobalScope/skipWaiting()}}

    + +

    The {{ServiceWorkerGlobalScope/skipWaiting()}} method allows this service worker to progress from the registration's waiting position to active even while service worker clients are using the registration.

    + +

    skipWaiting() method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run the following substeps in parallel: +
        +
      1. Set service worker's skip waiting flag
      2. +
      3. If service worker's state is installed, then: +
          +
        1. Run Activate algorithm, or its equivalent, passing service worker's registration as the argument.
        2. +
        +
      4. +
      5. Resolve promise with undefined.
      6. +
      +
    4. +
    5. Return promise.
    6. +
    +
    + +
    +

    Event handlers

    + +

    The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    event handlerevent handler event type
    oninstallinstall
    onactivateactivate
    onfetchfetch
    onmessagemessage
    +
    +
    + +
    +

    {{Client}}

    + +
    +      [Exposed=ServiceWorker]
    +      interface Client {
    +        readonly attribute USVString url;
    +        readonly attribute FrameType frameType;
    +        readonly attribute DOMString id;
    +        void postMessage(any message, optional sequence<Transferable> transfer);
    +      };
    +
    +      [Exposed=ServiceWorker]
    +      interface WindowClient : Client {
    +        readonly attribute VisibilityState visibilityState;
    +        readonly attribute boolean focused;
    +        [NewObject] Promise<WindowClient> focus();
    +        [NewObject] Promise<WindowClient> navigate(USVString url);
    +      };
    +
    +      enum FrameType {
    +        "auxiliary",
    +        "top-level",
    +        "nested",
    +        "none"
    +      };
    +    
    + +

    A Client object has an associated service worker client (a service worker client).

    + +

    A WindowClient object has an associated visibility state, which is one of {{Document/visibilityState}} attribute value.

    + +

    A {{WindowClient}} object has an associated focus state, which is either true or false (initially false).

    + +
    +

    {{Client/url}}

    + +

    The url attribute must return the context object's associated service worker client's serialized creation url.

    +
    + +
    +

    {{Client/frameType}}

    + +

    The frameType attribute must return the value (in FrameType enumeration) corresponding to the first matching statement, switching on service worker client's frame type:

    + +
    +
    auxiliary
    +
    "auxiliary" +

    The window client's global object's browsing context is an auxiliary browsing context.

    + +
    top-level
    +
    "top-level" +

    The window client's global object's browsing context is a top-level browsing context.

    + +
    nested
    +
    "nested" +

    The window client's global object's browsing context is a nested browsing context.

    + +
    none
    +
    "none"
    +
    +
    + +
    +

    {{Client/id}}

    + +

    The id attribute must return its associated service worker client's id.

    +
    + +
    +

    {{Client/postMessage(message, transfer)}}

    + +

    The postMessage(message, transfer) method must run these steps or their equivalent:

    + +
      +
    1. Let newPorts be an empty array.
    2. +
    3. Let transferMap be an empty association list of {{Transferable}} objects to placeholder objects.
    4. +
    5. If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. If any object is listed in transfer more than once, or any of the {{Transferable}} objects listed in transfer are marked as neutered, then throw a "{{DataCloneError}}" exception and abort these steps.
      2. +
      3. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a {{MessagePort}} object, also append the placeholder object to newPorts.
      4. +
      +
    6. +
    7. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps.
    8. +
    9. Let destination be the {{ServiceWorkerContainer}} object whose service worker client is the context object's service worker client.
    10. +
    11. If destination is null, throw an "{{InvalidStateError}}" exception.
    12. +
    13. If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. Let newOwner be the destination's service worker client.
      2. +
      3. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts).
      4. +
      +
    14. +
    15. Make newPorts into a read only array.
    16. +
    17. Queue a task that runs the following steps: +
        +
      1. Create an event e that uses the {{ServiceWorkerMessageEvent}} interface, with the event type message, which does not bubble, is not cancelable, and has no default action.
      2. +
      3. Let the {{ServiceWorkerMessageEvent/data}} attribute of e be initialized to clonedMessage.
      4. +
      5. Let the {{ServiceWorkerMessageEvent/origin}} attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object.
      6. +
      7. Let the {{ServiceWorkerMessageEvent/source}} attribute of e be initialized to a {{ServiceWorker}} object, which represents the service worker associated with the global object specified by the incumbent settings object.
      8. +
      9. Let the {{ServiceWorkerMessageEvent/ports}} attribute of e be initialized to newPorts.
      10. +
      11. Dispatch e at destination.
      12. +
      +

      The task must use the DOM manipulation task source, and, for those where the event loop specified by the target {{ServiceWorkerContainer}} object's service worker client is a browsing context event loop, must be associated with the responsible document specified by that target {{ServiceWorkerContainer}} object's service worker client.

      +
    18. +
    +
    + +
    +

    {{WindowClient/visibilityState}}

    + +

    The visibilityState attribute must return the context object's visibility state.

    +
    + +
    +

    {{WindowClient/focused}}

    + +

    The focused attribute must return the context object's focus state.

    +
    + +
    +

    {{WindowClient/focus()}}

    + +

    The focus() method must run these steps or their equivalent:

    + +
      +
    1. If this algorithm is not allowed to show a popup, return a promise rejected with an "{{InvalidAccessError}}" exception.
    2. +
    3. Let promise be a new promise.
    4. +
    5. Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
      2. +
      3. Let visibilityState be null.
      4. +
      5. Let focusState be null.
      6. +
      7. Queue a task task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
          +
        1. Run the focusing steps with browsingContext.
        2. +
        3. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
        4. +
        5. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
        6. +
        +
      8. +
      9. Wait for task to have executed.
      10. +
      11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with the context object's associated service worker client, visibilityState and focusState as the arguments.
      12. +
      13. If windowClient's focus state is true, resolve promise with windowClient.
      14. +
      15. Else, reject promise with a TypeError.
      16. +
      +
    6. +
    7. Return promise.
    8. +
    +
    + +
    +

    {{WindowClient/navigate(url)}}

    + +

    The navigate() method must run these steps or their equivalent:

    + +
      +
    1. Let url be the result of parsing url with entry settings object's API base URL.
    2. +
    3. If url is failure, return a promise rejected with a TypeError.
    4. +
    5. If url is about:blank, return a promise rejected with a TypeError.
    6. +
    7. If the context object's associated service worker client's active worker is not the incumbent settings object's global object's service worker, return a promise rejected with a TypeError.
    8. +
    9. Let promise be a new promise.
    10. +
    11. Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object's associated service worker client's global object's browsing context.
      2. +
      3. If browsingContext has discarded its {{Document}}, reject promise with a TypeError and abort these steps.
      4. +
      5. Let navigateFailed to false.
      6. +
      7. Let visibilityState be null.
      8. +
      9. Let focusState be null.
      10. +
      11. Queue a task task to run the following substeps on the context object's associated service worker client's responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate browsingContext to url with replacement enabled and exceptions enabled. The source browsing context must be browsingContext.
        2. +
        3. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set navigateFailed to true.
        4. +
        5. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
        6. +
        7. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
        8. +
        +
      12. +
      13. Wait for task to have executed (including its asynchronous steps).
      14. +
      15. If navigateFailed is true, reject promise with a TypeError and abort these steps.
      16. +
      17. If browsingContext's {{Window}} object's environment settings object's creation url's origin is not the same as the service worker's origin, then: +
          +
        1. Resolve promise with null.
        2. +
        3. Abort these steps.
        4. +
        +
      18. +
      19. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with browsingContext's {{Window}} object's environment settings object, visibilityState and focusState as the arguments.
      20. +
      21. Resolve promise with windowClient.
      22. +
      +
    12. +
    13. Return promise.
    14. +
    +
    +
    + +
    +

    {{Clients}}

    + +
    +      [Exposed=ServiceWorker]
    +      interface Clients {
    +        // The objects returned will be new instances every time
    +        [NewObject] Promise<any> get(DOMString id);
    +        [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
    +        [NewObject] Promise<WindowClient?> openWindow(USVString url);
    +        [NewObject] Promise<void> claim();
    +      };
    +    
    +
    +      dictionary ClientQueryOptions {
    +        boolean includeUncontrolled = false;
    +        ClientType type = "window";
    +      };
    +    
    +
    +      enum ClientType {
    +        "window",
    +        "worker",
    +        "sharedworker",
    +        "all"
    +      };
    +    
    + +

    The user agent must create a Clients object when a ServiceWorkerGlobalScope object is created and associate it with that object.

    + +
    +

    {{Clients/get(id)}}

    + +

    The get(id) method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run these substeps in parallel: +
        +
      1. For each service worker client client whose origin is the same as the associated service worker's origin: +
          +
        1. If client's id is id, then: +
            +
          1. If client is not a secure context, reject promise with a "{{SecurityError}}" exception and abort these steps.
          2. +
          3. If client is a window client, then: +
              +
            1. Let browsingContext be client's global object's browsing context.
            2. +
            3. Let visibilityState be null.
            4. +
            5. Let focusState be null.
            6. +
            7. Queue a task task to run the following substeps: +
                +
              1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
              2. +
              3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
              4. +
              +
            8. +
            9. Wait for task to have executed.
            10. +
            11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
            12. +
            13. Resolve promise with windowClient and abort these steps.
            14. +
            +
          4. +
          5. Else: +
              +
            1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
            2. +
            3. Resolve promise with clientObject and abort these steps.
            4. +
            +
          6. +
          +
        2. +
        +
      2. +
      3. Resolve promise with undefined.
      4. +
      +
    4. +
    5. Return promise.
    6. +
    +
    + +
    +

    {{Clients/matchAll(options)}}

    + +

    The matchAll(options) method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run these substeps in parallel: +
        +
      1. Let targetClients be an empty array.
      2. +
      3. For each service worker client client whose origin is the same as the associated service worker's origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop.
        2. +
        3. If options.{{ClientQueryOptions/includeUncontrolled}} is false, then: +
            +
          1. If client's active worker is the associated service worker, add client to targetClients.
          2. +
          +
        4. +
        5. Else: +
            +
          1. Add client to targetClients.
          2. +
          +
        6. +
        +
      4. +
      5. Let matchedClients be an empty array.
      6. +
      7. For each service worker client client in targetClients, in the most recently focused order for window clients: +
          +
        1. If options.{{ClientQueryOptions/type}} is "window", and client is a window client, then: +
            +
          1. Let browsingContext be client's global object's browsing context.
          2. +
          3. Let visibilityState be null.
          4. +
          5. Let focusState be null.
          6. +
          7. Queue a task task to run the following substeps on client's responsible event loop using the user interaction task source: +
              +
            1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
            2. +
            3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
            4. +
            +
          8. +
          9. Wait for task to have executed. +

            Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

            +
          10. +
          11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
          12. +
          13. Add windowClient to matchedClients.
          14. +
          +
        2. +
        3. Else if options.{{ClientQueryOptions/type}} is "worker" and client is a dedicated worker client, or options.{{ClientQueryOptions/type}} is "sharedworker" and client is a shared worker client, then: +
            +
          1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
          2. +
          3. Add clientObject to matchedClients.
          4. +
          +
        4. +
        5. Else if options.{{ClientQueryOptions/type}} is "all", then: +
            +
          1. If client is a window client, then: +
              +
            1. Let browsingContext be client's global object's browsing context.
            2. +
            3. Let visibilityState be null.
            4. +
            5. Let focusState be null.
            6. +
            7. Queue a task task to run the following substeps on client's responsible event loop using the user interaction task source: +
                +
              1. Set visibilityState to browsingContext's active document's {{Document/visibilityState}} attribute value.
              2. +
              3. Set focusState to the result of running the has focus steps with browsingContext's active document as the argument.
              4. +
              +
            8. +
            9. Wait for task to have executed. +

              Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

              +
            10. +
            11. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments.
            12. +
            13. Add windowClient to matchedClients.
            14. +
            +
          2. +
          3. Else: +
              +
            1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument.
            2. +
            3. Add clientObject to matchedClients.
            4. +
            +
          4. +
          +
        +
      8. +
      9. Resolve promise with matchedClients.
      10. +
      +
    4. +
    5. Return promise.
    6. +
    +
    + +
    +

    {{Clients/openWindow(url)}}

    + +

    The openWindow(url) method must run these steps or their equivalent:

    + +
      +
    1. Let url be the result of parsing url with entry settings object's API base URL.
    2. +
    3. If url is failure, return a promise rejected with a TypeError.
    4. +
    5. If url is about:blank, return a promise rejected with a TypeError.
    6. +
    7. If this algorithm is not allowed to show a popup, return a promise rejected with an "<{{InvalidAccessError}}" exception.
    8. +
    9. Let promise be a new promise.
    10. +
    11. Run these substeps in parallel: +
        +
      1. Let newContext be a new top-level browsing context.
      2. +
      3. Let openWindowFailed to false.
      4. +
      5. Let visibilityState be null.
      6. +
      7. Let focusState be null.
      8. +
      9. Queue a task task to run the following substeps on newContext's {{Window}} object's environment settings object's responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate newContext to url, with exceptions enabled and replacement enabled.
        2. +
        3. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set openWindowFailed to true.
        4. +
        5. Set visibilityState to newContext's active document's {{Document/visibilityState}} attribute value.
        6. +
        7. Set focusState to the result of running the has focus steps with newContext's active document as the argument.
        8. +
        +
      10. +
      11. Wait for task to have executed (including its asynchronous steps).
      12. +
      13. If openWindowFailed is true, reject promise with a TypeError and abort these steps.
      14. +
      15. If newContext's {{Window}} object's environment settings object's creation url's origin is not the same as the service worker's origin, then: +
          +
        1. Resolve promise with null.
        2. +
        3. Abort these steps.
        4. +
        +
      16. +
      17. Let client be the result of running Create Window Client algorithm, or its equivalent, with newContext's {{Window}} object's environment settings object, visibilityState and focusState as the arguments.
      18. +
      19. Resolve promise with client.
      20. +
      +
    12. +
    13. Return promise.
    14. +
    +
    + +
    +

    {{Clients/claim()}}

    + +

    The claim() method must run these steps or their equivalent:

    + +
      +
    1. If the service worker is not an active worker, return a promise rejected with an "{{InvalidStateError}}" exception.
    2. +
    3. Let promise be a new promise.
    4. +
    5. Run the following substeps in parallel: +
        +
      1. For each service worker client client whose origin is the same as the service worker's origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop.
        2. +
        3. Let registration be the result of running Match Service Worker Registration algorithm passing client's creation url as the argument.
        4. +
        5. If registration is not the service worker's containing service worker registration, continue to the next iteration of the loop.
        6. +
        7. If client's active worker is not the service worker, then: +
            +
          1. Invoke Handle Service Worker Client Unload with client as the argument.
          2. +
          3. Set client's active worker to service worker.
          4. +
          5. Invoke Notify Controller Change algorithm with client as the argument.
          6. +
          +
        8. +
        +
      2. +
      3. Resolve promise with undefined.
      4. +
      +
    6. +
    7. Return promise.
    8. +
    +
    +
    + +
    +

    {{ExtendableEvent}}

    + +
    +      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +      interface ExtendableEvent : Event {
    +        void waitUntil(Promise<any> f);
    +      };
    +    
    +
    +      dictionary ExtendableEventInit : EventInit {
    +        // Defined for the forward compatibility across the derived events
    +      };
    +    
    + +

    An ExtendableEvent object has an associated extend lifetime promises (an array of promises). It is initially set to null.

    + +

    Service workers have two lifecycle events, install and activate. Service workers use the {{ExtendableEvent}} interface for activate event and install event.

    + +

    Service worker extensions that define event handlers may also use or extend the {{ExtendableEvent}} interface.

    + +
    +

    {{ExtendableEvent/waitUntil(f)|event.waitUntil(f)}}

    + +

    {{ExtendableEvent/waitUntil(f)}} method extends the lifetime of the event.

    + +

    waitUntil(f) method must run these steps or their equivalent:

    + +
      +
    1. If the dispatch flag is unset, then: +
        +
      1. Throw an "{{InvalidStateError}}" exception.
      2. +
      3. Abort these steps.
      4. +
      +
    2. +
    3. Add f to extend lifetime promises.
    4. +
    + +

    In the task task in which the steps of waitUntil(f) is running, the user agent must run these steps or their equivalent:

    + +
      +
    1. Let extendLifetimePromises be an empty array.
    2. +
    3. For each event listener invoked: +
        +
      1. Let eventObject be the first argument passed to this event listener.
      2. +
      3. Append eventObject's extend lifetime promises to extendLifetimePromises.
      4. +
      +
    4. +
    5. Do not terminate the service worker whose responsible event loop is running task until waiting for all of extendLifetimePromises settles.
    6. +
    +

    However, the user agent may impose a time limit to this lifetime extension.

    + +

    Service workers and extensions that define event handlers may define their own behaviors, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

    + +

    Service workers define the following behaviors for install event and activate event:

    + +
      +
    • When called in {{ServiceWorkerGlobalScope/oninstall}}, it delays treating the installing worker as installed (i.e. a waiting worker) until the passed promise f resolves successfully. (See step 10.6.1 of Install algorithm.) If f rejects, the installation fails. This is primarily used to ensure that a service worker is not considered installed (i.e. a waiting worker) until all of the core caches it depends on are populated.
    • +
    • When called in {{ServiceWorkerGlobalScope/onactivate}}, it delays treating the active worker as activated until the passed promise f settles. (See step 13 of Activate algorithm.) This is primarily used to ensure that any functional events are not dispatched to the {{ServiceWorkerGlobalScope}} object that represents the service worker until it upgrades database schemas and deletes the outdated cache entries.
    • +
    +
    +
    + +
    +

    {{FetchEvent}}

    + +
    +      [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
    +      interface FetchEvent : ExtendableEvent {
    +        [SameObject] readonly attribute Request request;
    +        readonly attribute DOMString? clientId;
    +        readonly attribute boolean isReload;
    +
    +        void respondWith(Promise<Response> r);
    +      };
    +    
    +
    +      dictionary FetchEventInit : ExtendableEventInit {
    +        required Request request;
    +        DOMString? clientId = null;
    +        boolean isReload = false;
    +      };
    +    
    + +

    Service workers have an essential functional event fetch. For fetch event, service workers use the FetchEvent interface which extends the {{ExtendableEvent}} interface.

    + +

    Each event using {{FetchEvent}} interface has an associated potential response (a response), initially set to null, and the following associated flags that are initially unset: +

      +
    • wait to respond flag
    • +
    • respond-with entered flag
    • +
    • respond-with error flag
    • +
    +

    + +
    +

    {{FetchEvent/request|event.request}}

    + +

    request attribute must return the value it was initialized to.

    +
    + +
    +

    {{FetchEvent/clientId|event.clientId}}

    + +

    clientId attribute must return the value it was initialized to. When an event is created the attribute must be initialized to null.

    +
    + +
    +

    {{FetchEvent/isReload|event.isReload}}

    + +

    isReload attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

    + +

    Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

    +
    + +
    +

    {{FetchEvent/respondWith(r)|event.respondWith(r)}}

    + +

    Developers can set the argument r with either a promise that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

    + +

    respondWith(r) method must run these steps or their equivalent:

    + +
      +
    1. If the dispatch flag is unset, then: +
        +
      1. Throw an "{{InvalidStateError}}" exception.
      2. +
      3. Abort these steps.
      4. +
      +
    2. +
    3. If the respond-with entered flag is set, then: +
        +
      1. Throw an "{{InvalidStateError}}" exception.
      2. +
      3. Abort these steps.
      4. +
      +
    4. +
    5. Set the stop propagation flag and stop immediate propagation flag.
    6. +
    7. Set the respond-with entered flag.
    8. +
    9. Set the wait to respond flag.
    10. +
    11. Run the following substeps in parallel: +
        +
      1. Wait until r settles.
      2. +
      3. If r rejected, then: +
          +
        1. Set the respond-with error flag.
        2. +
        +
      4. +
      5. If r resolved with response, then: +
          +
        1. If response is a {{Response}} object, then: +
            +
          1. If response is disturbed or locked, then: +
              +
            1. Set the respond-with error flag.
            2. +
            +
          2. +
          3. Else: +
              +
            1. Let potentialResponse be a copy of response's associated response, except for its body.
            2. +
            3. If response's body is non-null, run these substeps: +
                +
              1. Set potentialResponse's body to response's body.
              2. +
              3. Let dummyStream be an empty ReadableStream object.
              4. +
              5. Set response's body to a new body whose stream is dummyStream.
              6. +
              7. Let reader be the result of getting a reader from dummyStream.
              8. +
              9. Read all bytes from dummyStream with reader.
              10. +
              +

              These substeps are meant to produce the observable equivalent of "piping" response's body's stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse's body's stream is now equal to what used to be response's, if response's original body is non-null.

              +

              These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

              +
            4. +
            5. Set the potential response to potentialResponse.
            6. +
            +
          4. +
          +
        2. +
        3. Else: +
            +
          1. Set the respond-with error flag.
          2. +
          +

          If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 22.1.)

          +
        4. +
        +
      6. +
      7. Unset the wait to respond flag.
      8. +
      +
    12. +
    +
    +
    + +
    +

    {{ExtendableMessageEvent}}

    + +
    +      [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
    +      interface ExtendableMessageEvent : ExtendableEvent {
    +        readonly attribute any data;
    +        readonly attribute DOMString origin;
    +        readonly attribute DOMString lastEventId;
    +        [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
    +        [SameObject] readonly attribute MessagePort[]? ports;
    +      };
    +    
    +
    +      dictionary ExtendableMessageEventInit : ExtendableEventInit {
    +        any data;
    +        DOMString origin;
    +        DOMString lastEventId;
    +        (Client or ServiceWorker or MessagePort)? source;
    +        sequence<MessagePort>? ports;
    +      };
    +    
    + +

    Service workers define the extendable message event that extends the {{Window/message}} event defined in [[!HTML]] to allow extending the lifetime of the event. For the message event, service workers use the ExtendableMessageEvent interface which extends the {{ExtendableEvent}} interface.

    + +
    +

    {{ExtendableMessageEvent/data|event.data}}

    + +

    The data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    + +
    +

    {{ExtendableMessageEvent/origin|event.origin}}

    + +

    The origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker client that sent the message.

    +
    + +
    +

    {{ExtendableMessageEvent/lastEventId|event.lastEventId}}

    + +

    The lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    + +
    +

    {{ExtendableMessageEvent/source|event.source}}

    + +

    The source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{Client}} object from which the message is sent.

    +
    + +
    +

    {{ExtendableMessageEvent/ports|event.ports}}

    + +

    The ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the {{MessagePort}} array being sent, if any.

    +
    +
    + +
    +

    Events

    + +

    The following events are dispatched on ServiceWorkerGlobalScope object:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Event nameInterfaceDispatched when…
    install{{ExtendableEvent}}[Lifecycle event] The service worker's containing service worker registration's installing worker changes. (See step 11.2 of the Install algorithm.)
    activate{{ExtendableEvent}}[Lifecycle event] The service worker's containing service worker registration's active worker changes. (See step 15.2 of the Activate algorithm.)
    fetch{{FetchEvent}}[Functional event] The http fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the service worker returns a response to the http fetch. The response, represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{GlobalFetch/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
    message{{ExtendableMessageEvent}}When it receives a message.
    +
    +
    + + +
    +

    Caches

    + +

    To allow authors to fully manage their content caches for offline use, the {{Window}} and the {{WorkerGlobalScope}} provide the asynchronous caching methods that open and manipulate {{Cache}} objects. An origin can have multiple, named {{Cache}} objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser's HTTP cache.

    + +
    +

    Constructs

    + +

    A fetching record is a Record {\[[key]], \[[value]]} where \[[key]] is a {{Request}} and \[[value]] is a {{Response}}.

    +

    A fetching record has an associated incumbent record (a fetching record). It is initially set to null.

    +

    A request to response map is a List of fetching records.

    + +

    A name to cache map is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a string that represents a name of the {{Cache}} object and \[[value]] is a {{Cache}} object.

    + +

    Each origin has an associated name to cache map.

    +
    + +
    +

    Understanding Cache Lifetimes

    + +

    The {{Cache}} instances are not part of the browser's HTTP cache. The {{Cache}} objects are exactly what authors have to manage themselves. The {{Cache}} objects do not get updated unless authors explicitly request them to be. The {{Cache}} objects do not expire unless authors delete the entries. The {{Cache}} objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

    +
    + +
    +

    {{Window/caches|self.caches}}

    + +
    +      partial interface Window {
    +        [SameObject] readonly attribute CacheStorage caches;
    +      };
    +
    +      partial interface WorkerGlobalScope {
    +        [SameObject] readonly attribute CacheStorage caches;
    +      };
    +    
    + +
    +

    {{Window/caches}}

    + +

    caches attribute must return the {{CacheStorage}} object that is associated with the context object.

    +
    +
    + +
    +

    {{Cache}}

    + +
    +      [Exposed=(Window,Worker)]
    +      interface Cache {
    +        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +        [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
    +        [NewObject] Promise<void> add(RequestInfo request);
    +        [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
    +        [NewObject] Promise<void> put(RequestInfo request, Response response);
    +        [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
    +        [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
    +      };
    +    
    +
    +      dictionary CacheQueryOptions {
    +        boolean ignoreSearch = false;
    +        boolean ignoreMethod = false;
    +        boolean ignoreVary = false;
    +        DOMString cacheName;
    +      };
    +    
    +
    +      dictionary CacheBatchOperation {
    +        DOMString type;
    +        Request request;
    +        Response response;
    +        CacheQueryOptions options;
    +      };
    +    
    + +

    A Cache object represents a request to response map. Multiple separate objects implementing the {{Cache}} interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

    + +

    {{Cache}} objects are always enumerable via {{Window/caches|self.caches}} in insertion order (per ECMAScript 6 Map objects).

    + +
    +

    {{Cache/match(request, options)}}

    + +

    match(request, options) method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run these substeps in parallel: +
        +
      1. Let p be the result of running the algorithm specified in {{Cache/matchAll(request, options)}} method with request and options as the arguments.
      2. +
      3. Wait until p settles.
      4. +
      5. If p rejects with an exception, then: +
          +
        1. Reject promise with that exception.
        2. +
        +
      6. +
      7. Else if p resolves with an array, responseArray, then: +
          +
        1. If responseArray is an empty array, then: +
            +
          1. Resolve promise with undefined.
          2. +
          +
        2. +
        3. Else: +
            +
          1. Resolve promise with the first element of responseArray.
          2. +
          +
        4. +
        +
      8. +
      +
    4. +
    5. Return promise.
    6. +
    +
    + +
    +

    {{Cache/matchAll(request, options)}}

    + +

    matchAll(request, options) method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run these substeps in parallel: +
        +
      1. Let responseArray be an empty array.
      2. +
      3. If the optional argument request is omitted, then: +
          +
        1. For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add a copy of entry.\[[value]] to responseArray.
          2. +
          +
        2. +
        3. Resolve promise with responseArray.
        4. +
        5. Abort these steps.
        6. +
        +
      4. +
      5. Else: +
          +
        1. Let r be null.
        2. +
        3. If request is a {{Request}} object, then: +
            +
          1. Set r to request's request.
          2. +
          3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
          4. +
          +
        4. +
        5. Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
          2. +
          +
        6. +
        7. Set r's url's fragment to null.
        8. +
        9. Let entries be the result of running Query Cache algorithm passing a {{Request}} object associated with r and options as the arguments.
        10. +
        11. For each entry of entries: +
            +
          1. Let response be null.
          2. +
          3. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, set response to a copy of incumbentRecord.\[[value]].
          4. +
          5. Else, set response to a copy of entry[1].
          6. +
          7. If r's method is `HEAD` and options.ignoreMethod is false, then: +
              +
            1. Let actualResponse be response's associated response, if response's associated response is not a filtered response, and to response's associated response's internal response otherwise.
            2. +
            3. Set actualResponse's body to null.
            4. +
            +
          8. +
          9. Add response to responseArray.
          10. +
          +
        12. +
        13. Resolve promise with responseArray.
        14. +
        +
      6. +
      +
    4. +
    5. Return promise.
    6. +
    +
    + +
    +

    {{Cache/add(request)}}

    + +

    add(request) method must run these steps or their equivalent:

    + +
      +
    1. Let requests be an array containing only request.
    2. +
    3. Set responseArrayPromise to the result of running the algorithm specified in {{Cache/addAll(requests)}} passing requests as the argument.
    4. +
    5. Return the result of transforming responseArrayPromise with a fulfillment handler that returns undefined.
    6. +
    +
    + +
    +

    {{Cache/addAll(requests)}}

    + +

    addAll(requests) method must run these steps or their equivalent:

    + +
      +
    1. Let responsePromiseArray be an empty array.
    2. +
    3. Let requestArray be an empty array.
    4. +
    5. For each request whose type is {{Request}} in requests: +
        +
      1. Let r be request's request.
      2. +
      3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
      4. +
      +
    6. +
    7. For each request in requests: +
        +
      1. Let r be the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
      2. +
      3. If r's url's scheme is not one of "http" and "https", then: +
          +
        1. Terminate all the ongoing fetches initiated by requests with reason fatal.
        2. +
        3. Break the loop.
        4. +
        +
      4. +
      5. Set r's url's fragment to null.
      6. +
      7. Set r's initiator to "fetch" and destination to "subresource".
      8. +
      9. Add a {{Request}} object associated with r to requestArray.
      10. +
      11. Let responsePromise be a new promise.
      12. +
      13. Run the following substeps in parallel: +
          +
        • Fetch r.
        • +
        • To process response for response, run these substeps: +
            +
          1. If response's type is error, or response's status is not an ok status, reject responsePromise with a TypeError.
          2. +
          3. Else if response's header list contains a header named `Vary`, then: +
              +
            1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
            2. +
            3. Let matchAsterisk be false.
            4. +
            5. For each f in varyHeaders: +
                +
              1. If f matches "*", set matchAsterisk to true and break the loop.
              2. +
              +
            6. +
            7. If matchAsterisk is true, reject responsePromise with a TypeError.
            8. +
            9. Else, resolve responsePromise with a new {{Response}} object associated with response and a new {{Headers}} object whose guard is "immutable".
            10. +
            +
          4. +
          5. Else, resolve responsePromise with a new {{Response}} object associated with response and a new {{Headers}} object whose guard is "immutable".
          6. +
          +

          This step ensures that the promise for this fetch resolves as soon as the response's headers become available.

          +
        • +
        • To process response body for response, do nothing.
        • +
        • To process response end-of-file for response, do nothing.
        • +
        +
      14. +
      15. Add responsePromise to responsePromiseArray.
      16. +
      +
    8. +
    9. Let p be waiting for all of responsePromiseArray.
    10. +
    11. Return the result of transforming p with a fulfillment handler that, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. Let operations be an empty array.
      2. +
      3. For each response in responseArray with the index index: +
          +
        1. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
        2. +
        3. Set the {{CacheBatchOperation/type}} dictionary member of o to "put".
        4. +
        5. Set the {{CacheBatchOperation/request}} dictionary member of o to requestArray[index].
        6. +
        7. Set the {{CacheBatchOperation/response}} dictionary member of o to response.
        8. +
        9. Add o to operations.
        10. +
        +
      4. +
      5. Let resultPromise be the result of running Batch Cache Operations algorithm passing operations as the argument.
      6. +
      7. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
          +
        1. Let responseBodyPromiseArray be an empty array.
        2. +
        3. For each response in responses: +
            +
          1. Let responseBodyPromise be a new promise.
          2. +
          3. Run the following substeps in parallel: +
              +
            1. Wait for either end-of-file to have been pushed to response's associated response r's body or for r to have a termination reason.
            2. +
            3. If r had a termination reason, then: +
                +
              1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
                  +
                1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
                2. +
                +
              2. +
              3. Else: +
                  +
                1. Delete fetchingRecord from request to response map.
                2. +
                +
              4. +
              5. Reject responseBodyPromise with a TypeError.
              6. +
              +
            4. +
            5. Else: +
                +
              1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
              2. +
              3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.\[[key]] as the argument.
              4. +
              5. For each invalidRecord in invalidRecords: +
                  +
                1. If invalidRecord is not fetchingRecord, delete it from request to response map.
                2. +
                +
              6. +
              7. Resolve responseBodyPromise with response.
              8. +
              +
            6. +
            +
          4. +
          5. Add responseBodyPromise to responseBodyPromiseArray.
          6. +
          +
        4. +
        5. Let q be waiting for all of responseBodyPromiseArray.
        6. +
        7. Return the result of transforming q with a fulfillment handler that returns undefined.
        8. +
        +
      8. +
      +
    12. +
    +
    + +
    +

    {{Cache/put(request, response)}}

    + +

    put(request, response) method must run these steps or their equivalent:

    + +
      +
    1. Let r be null.
    2. +
    3. If request is a {{Request}} object, then: +
        +
      1. Set r to request's request.
      2. +
      3. If r's url's scheme is not one of "http" and "https", or r's method is not `GET`, return a promise rejected with a TypeError.
      4. +
      +
    4. +
    5. Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
      2. +
      3. If r's url's scheme is not one of "http" and "https", return a promise rejected with a TypeError.
      4. +
      +
    6. +
    7. Set r's url's fragment to null.
    8. +
    9. If response's associated response's header list contains a header named `Vary`, then: +
        +
      1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
      2. +
      3. For each f in varyHeaders: +
          +
        1. If f matches "*", return a promise rejected with a TypeError.
        2. +
        +
      4. +
      +
    10. +
    11. If response is disturbed or locked, return a promise rejected with a TypeError.
    12. +
    13. Let newResponse be a new {{Response}} object associated with response's associated response and a new {{Headers}} object whose guard is response's {{Headers}}' guard.
    14. +
    15. If response's body is non-null, run these substeps: +
        +
      1. Let dummyStream be an empty ReadableStream object.
      2. +
      3. Set response's body to a new body whose stream is dummyStream.
      4. +
      5. Let reader be the result of getting a reader from dummyStream.
      6. +
      7. Read all bytes from dummyStream with reader.
      8. +
      +
    16. +
    17. Let operations be an empty array.
    18. +
    19. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
    20. +
    21. Set the {{CacheBatchOperation/type}} dictionary member of o to "put".
    22. +
    23. Set the {{CacheBatchOperation/request}} dictionary member of o to a {{Request}} object associated with r.
    24. +
    25. Set the {{CacheBatchOperation/response}} dictionary member of o to newResponse.
    26. +
    27. Add o to operations.
    28. +
    29. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument.
    30. +
    31. Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
        +
      1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r's body or for r to have a termination reason.
      2. +
      3. If r had a termination reason, then: +
          +
        1. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
            +
          1. Set fetchingRecord in request to response map to the copy of incumbentRecord.
          2. +
          +
        2. +
        3. Else: +
            +
          1. Delete fetchingRecord from request to response map.
          2. +
          +
        4. +
        5. Throw a TypeError.
        6. +
        +
      4. +
      5. Else: +
          +
        1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord.
        2. +
        3. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.\[[key]] as the argument.
        4. +
        5. For each invalidRecord in invalidRecords: +
            +
          1. If invalidRecord is not fetchingRecord, delete it from request to response map.
          2. +
          +
        6. +
        7. Return undefined.
        8. +
        +
      6. +
      +
    32. +
    +
    + +
    +

    {{Cache/delete(request, options)}}

    + +

    delete(request, options) method must run these steps or their equivalent:

    + +
      +
    1. Let r be null.
    2. +
    3. If request is a {{Request}} object, then: +
        +
      1. Set r to request's request.
      2. +
      3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, return a promise resolved with false.
      4. +
      +
    4. +
    5. Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
      2. +
      +
    6. +
    7. Set r's url's fragment to null.
    8. +
    9. Let operations be an empty array.
    10. +
    11. Let o be an empty object representing a {{CacheBatchOperation}} dictionary.
    12. +
    13. Set the {{CacheBatchOperation/type}} dictionary member of o to "delete".
    14. +
    15. Set the {{CacheBatchOperation/request}} dictionary member of o to a {{Request}} object associated with r.
    16. +
    17. Set the {{CacheBatchOperation/options}} dictionary member of o to options.
    18. +
    19. Add o to operations.
    20. +
    21. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument.
    22. +
    23. Return the result of transforming resultPromise with a fulfillment handler, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. If responseArray is not null, return true.
      2. +
      3. Else, return false.
      4. +
      +
    24. +
    +
    + +
    +

    {{Cache/keys(request, options)}}

    + +

    keys(request, options) method must run these steps or their equivalent:

    + +
      +
    1. Let promise be a new promise.
    2. +
    3. Run these substeps in parallel: +
        +
      1. Let resultArray be an empty array.
      2. +
      3. If the optional argument request is omitted, then: +
          +
        1. For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add entry.\[[key]] to resultArray.
          2. +
          +
        2. +
        +
      4. +
      5. Else: +
          +
        1. Let r be null.
        2. +
        3. If request is a {{Request}} object, then: +
            +
          1. Set r to request's request.
          2. +
          3. If r's method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array.
          4. +
          +
        4. +
        5. Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of {{Request}} as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception.
          2. +
          +
        6. +
        7. Set r's url's fragment to null.
        8. +
        9. Let requestResponseArray be the result of running Query Cache algorithm passing a {{Request}} object that represents r and options as the arguments.
        10. +
        11. For each requestResponse in requestResponseArray: +
            +
          1. Add requestResponse[0] to resultArray.
          2. +
          +
        12. +
        +
      6. +
      7. Resolve promise with resultArray.
      8. +
      +
    4. +
    5. Return promise.
    6. +
    +
    +
    + +
    +

    {{CacheStorage}}

    + +
    +      [Exposed=(Window,Worker)]
    +      interface CacheStorage {
    +        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +        [NewObject] Promise<boolean> has(DOMString cacheName);
    +        [NewObject] Promise<Cache> open(DOMString cacheName);
    +        [NewObject] Promise<boolean> delete(DOMString cacheName);
    +        [NewObject] Promise<sequence<DOMString>> keys();
    +      };
    +    
    + + +

    {{CacheStorage}} interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

    + +

    The user agent must create a {{CacheStorage}} object when a {{Window}} object or a {{WorkerGlobalScope}} object is created and associate it with that object.

    + +

    A CacheStorage object represents a name to cache map of its associated global object's environment settings object's origin. Multiple separate objects implementing the {{CacheStorage}} interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

    + +
    +

    {{CacheStorage/match(request, options)}}

    + +

    match(request, options) method must run these steps or their equivalent:

    + +
      +
    1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    2. +
    3. If options.{{CacheQueryOptions/cacheName}} is present, then: +
        +
      1. Return a new promise p and run the following substeps in parallel: +
          +
        1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
            +
          1. If options.{{CacheQueryOptions/cacheName}} matches entry.\[[key]], then: +
              +
            1. Resolve p with the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with request and options as the arguments (providing entry.\[[value]] as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.)
            2. +
            3. Abort these steps.
            4. +
            +
          2. +
          +
        2. +
        3. Reject p with a "{{NotFoundError}}" exception.
        4. +
        +
      2. +
      +
    4. +
    5. Else: +
        +
      1. Let p be a promise resolved with undefined.
      2. +
      3. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. Set p to the result of transforming itself with a fulfillment handler that, when called with argument v, performs the following substeps in parallel: +
            +
          1. If v is not undefined, return v.
          2. +
          3. Return the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with request and options as the arguments (providing entry.\[[value]] as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.)
          4. +
          +
        2. +
        +
      4. +
      5. Return p.
      6. +
      +
    6. +
    +
    + +
    +

    {{CacheStorage/has(cacheName)}}

    + +

    has(cacheName) method must run these steps or their equivalent:

    + +
      +
    1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    2. +
    3. Return a promise p resolved with the result of running the following substeps: +
        +
      1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. If cacheName matches entry.\[[key]], then: +
            +
          1. Return true.
          2. +
          +
        2. +
        +
      2. +
      3. Return false.
      4. +
      +
    4. +
    +
    + +
    +

    {{CacheStorage/open(cacheName)}}

    + +

    open(cacheName) method must run these steps or their equivalent:

    + +
      +
    1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    2. +
    3. Let p be a new promise.
    4. +
    5. Run the following substeps: +
        +
      1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. If cacheName matches entry.\[[key]], then: +
            +
          1. Resolve p with a new {{Cache}} object which is a copy of entry.\[[value]].
          2. +
          3. Abort these steps.
          4. +
          +
        2. +
        +
      2. +
      3. Let cache be a new {{Cache}} object.
      4. +
      5. Set a newly-created Record {\[[key]]: cacheName, \[[value]]: cache} to name to cache map. If this cache write operation failed due to exceeding the granted quota limit, reject p with a "{{QuotaExceededError}}" exception and abort these steps.
      6. +
      7. Resolve p with cache.
      8. +
      +
    6. +
    7. Return p.
    8. +
    +
    + +
    +

    {{CacheStorage/delete(cacheName)}}

    + +

    delete(cacheName) method must run these steps or their equivalent:

    + +
      +
    1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    2. +
    3. Let p be the result of running the algorithm specified in {{CacheStorage/has(cacheName)}} method with cacheName as the argument.
    4. +
    5. Return the result of transforming p with a fulfillment handler that, when called with argument cacheExists, performs the following substeps in parallel: +
        +
      1. If cacheExists is true, then: +
          +
        1. Delete a Record {\[[key]], \[[value]]} entry from its name to cache map where cacheName matches entry.\[[key]].
        2. +
        3. Return true.
        4. +
        5. Abort these steps.
        6. +
        +

        After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.

        +
      2. +
      3. Else: +
          +
        1. Return false.
        2. +
        +
      4. +
      +
    6. +
    +
    + +
    +

    {{CacheStorage/keys()}}

    + +

    keys() method must run these steps or their equivalent:

    + +

    The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

    + +
      +
    1. If the context object's associated global object's environment settings object is not a secure context, return a promise rejected with a "{{SecurityError}}" exception.
    2. +
    3. Let resultArray be an empty array.
    4. +
    5. Return a promise p resolved with the result of running the following substeps: +
        +
      1. For each Record {\[[key]], \[[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. Add entry.\[[key]] to resultArray.
        2. +
        +
      2. +
      3. Return resultArray.
      4. +
      +
    6. +
    +
    +
    +
    + +
    +

    Security Considerations

    + +
    +

    Secure Context

    + +

    Service workers must execute in secure contexts. Service worker clients must also be secure contexts to register a service worker registration, to get access to the service worker registrations and the service workers, to do messaging with the service workers, and to be manipulated by the service workers. This effectively means that service workers and their service worker clients should be hosted over HTTPS. A user agent may allow localhost, 127.0.0.0/8, and ::1/128 for development purpose. (Note that they may still be secure contexts.) The primary reason for this restriction is to protect users from the risks associated with insecure contexts.

    +
    + +
    +

    Content Security Policy

    + +

    Whenever a user agent invokes Run Service Worker algorithm with a service worker serviceWorker: +

      +
    • If serviceWorker's script resource was delivered with a Content-Security-Policy HTTP header containing the value policy, the user agent must enforce policy for serviceWorker.
    • +
    • If serviceWorker's script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value policy, the user agent must monitor policy for serviceWorker.
    • +
    +

    +

    The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).

    +
    + +
    +

    Origin Relativity

    + +
    +

    Origin restriction

    + + This section is non-normative. + +

    A Service worker executes in the registering service worker client's origin. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

    +
    + +
    +

    {{WorkerGlobalScope/importScripts(urls)}}

    + +

    When the importScripts(urls) method is called on a {{ServiceWorkerGlobalScope}} object, the user agent must import scripts into worker global scope, with the following options:

    + +

    To validate the state, the user agent must do nothing.

    + +

    To get a fetch result, the user agent must run the following steps:

    + +
      +
    1. Let serviceWorker be the settings object's global object's service worker.
    2. +
    3. If serviceWorker's imported scripts updated flag is unset, then: +
        +
      1. Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set.
      2. +
      +
    4. +
    5. Else: +
        +
      1. If there exists a corresponding Record record for url in serviceWorker's script resource map, set the script resource to record.\[[value]].
      2. +
      3. Else, set the script resource to null.
      4. +
      +
    6. +
    + +

    To postprocess the fetch result, the user agent must run the following steps:

    + +
      +
    1. If serviceWorker's imported scripts updated flag is unset, then: +
        +
      1. If the fetching attempt failed (e.g. the server returned a 4xx or 5xx status code or equivalent, or there was a DNS error), throw a "{{NetworkError}}" exception and abort all these steps.
      2. +
      3. Else: +
          +
        1. If there exists a corresponding Record record for the resulting absolute URL url in serviceWorker's script resource map, set record.\[[value]] to the fetched script resource.
        2. +
        3. Else, set a newly-created Record {\[[key]]: url, \[[value]]: the fetched script resource} to serviceWorker's script resource map.
        4. +
        +
      4. +
      +
    2. +
    3. Else, if the script resource is null, throw a "{{NetworkError}}" exception and abort all these steps.
    4. +
    +
    +
    + +
    +

    Cross-Origin Resources and CORS

    + + This section is non-normative. + +

    Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to fetch many sorts of off-origin resources when appropriate CORS headers are set.

    +

    Service workers enable this by allowing {{Cache|Caches}} to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding responses are basic filtered response, the objects stored are {{Response}} objects whose corresponding responses are either CORS filtered responses or opaque filtered responses. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding responses are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases.

    +
    + +
    +

    Implementer Concerns

    + + This section is non-normative. + +

    The implementers are encouraged to note: +

      +
    • Plug-ins should not load via service workers. As plug-ins may get their security origins from their own urls, the embedding service worker cannot handle it. For this reason, the Handle Fetch algorithm makes the potential-navigation-or-subresource request (whose context is either <embed> or <object>) immediately fallback to the network without dispatching fetch event.
    • +
    • Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with service workers.
    • +
    +

    +
    + +
    +

    Privacy

    + +

    Service workers introduce new persistent storage features including scope to registration map (for service worker registrations and their service workers), request to response map and name to cache map (for caches), and script resource map (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages should be cleared when users intend to clear them and should maintain and interoperate with existing user controls e.g. purging all existing persistent storages.

    +
    +
    + +
    +

    Storage Considerations

    + +

    Service workers should take a dependency on Quota Management API that extends the ServiceWorkerGlobalScope with the event listeners {{ServiceWorkerGlobalScope/onbeforeevicted}} and {{ServiceWorkerGlobalScope/onevicted}} to detect a storage pressure and give pre-eviction information to the application.

    +

    The cache write operations in service workers when failed due to exceeding the granted quota limit should throw "{{QuotaExceededError}}" exception.

    + + +
    +

    Extensibility

    + +

    Service workers are extensible from other specifications.

    + +
    +

    Define API bound to Service Worker Registration

    + +

    Specifications may define an API tied to a service worker registration by using partial interface definition to the {{ServiceWorkerRegistration}} interface where it may define the specification specific attributes and methods:

    + +
    +      partial interface ServiceWorkerRegistration {
    +        // e.g. define an API namespace
    +        readonly attribute APISpaceType APISpace;
    +        // e.g. define a method
    +        Promise<T> methodName(list of arguments);
    +      };
    +    
    +
    + +
    +

    Define Functional Event

    + +

    Specifications may define a functional event by extending {{ExtendableEvent}} interface:

    + +
    +      // e.g. define FunctionalEvent interface
    +      interface FunctionalEvent : ExtendableEvent {
    +        // add a functional event's own attributes and methods
    +      };
    +    
    +
    + +
    +

    Define Event Handler

    + +

    Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the {{ServiceWorkerGlobalScope}} interface:

    + +
    +      partial interface ServiceWorkerGlobalScope {
    +        attribute EventHandler onfunctionalevent;
    +      };
    +    
    +
    + +
    +

    Request Functional Event Dispatch

    + +

    To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

    + +

    Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a {{ServiceWorkerGlobalScope}} object) at which it may fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm.

    + +

    See an example hook defined in Notifications API.

    +
    +
    + +
    +

    Appendix A: Algorithms

    + +

    The following definitions are the user agent's internal data structures used throughout the specification.

    + +

    A scope to registration map is a List of the Record {\[[key]], \[[value]]} where \[[key]] is a string that represents a scope url and \[[value]] is a service worker registration.

    + +

    A job is an abstraction of one of register, update, and unregister request for a service worker registration.

    + +

    A job has a job type, which is one of register, update, and unregister.

    + +

    A job has a scope url (a URL).

    + +

    A job has a script url (a URL).

    + +

    A job has a client (a service worker client). It is initially null.

    + +

    A job has a promise (a promise). It is initially null.

    + +

    A job has a list of equivalent job promises (a list of promises). It is initially the empty list.

    + +

    A job has a force bypass cache flag It is initially unset.

    + +

    Two jobs are equivalent when their job type is the same and: +

    +

    + +

    A job queue is a queue used to synchronize the set of concurrent jobs. The job queue contains jobs as its elements. The job queue should satisfy the general properties of FIFO queue. A user agent must maintain a separate job queue for each service worker registration keyed by its scope url. A job queue is initially empty. Unless stated otherwise, the job queue referenced from the algorithm steps is a job queue for the job's scope url.

    + +
    +

    Create Job

    + +
    +
    Input
    +
    jobType, a job type
    +
    scopeURL, a URL
    +
    scriptURL, a URL
    +
    promise, a promise
    +
    client, a service worker client
    +
    Output
    +
    job, a job
    +
    +
      +
    1. Let job be a new job.
    2. +
    3. Set job's job type to jobType.
    4. +
    5. Set job's scope url to scopeURL.
    6. +
    7. Set job's script url to scriptURL.
    8. +
    9. Set job's promise to promise.
    10. +
    11. Set job's client to client.
    12. +
    13. Return job.
    14. +
    +
    + +
    +

    Schedule Job

    + +
    +
    Input
    +
    job, a job
    +
    Output
    +
    none
    +
    +
      +
    1. If the job queue is empty, then: +
        +
      1. Push job to the job queue and invoke Run Job.
      2. +
      +
    2. +
    3. Else: +
        +
      1. Let lastJob be the element at the back of the job queue.
      2. +
      3. If job is equivalent to lastJob and lastJob's promise has not settled, append job's promise to lastJob's list of equivalent job promises.
      4. +
      5. Else, push job to the job queue.
      6. +
      +
    4. +
    +
    + +
    +

    Run Job

    + +
    +
    Input
    +
    none
    +
    Output
    +
    none
    +
    +
      +
    1. Assert: the job queue is not empty.
    2. +
    3. Let job be the element in the front of the job queue.
    4. +
    5. If job's job type is register, invoke Register with job and continue running these steps in parallel.
    6. +
    7. Else if job's job type is update, invoke Update with job and continue running these steps in parallel. +

      For a register job and an update job, the user agent delays invoking Register and Update respectively until after the document initiated the job has been dispatched {{Document/DOMContentLoaded}} event. If the job's client is a worker client, it is delayed until after the worker script has evaluated.

      +
    8. +
    9. Else if job's job type is unregister, invoke Unregister with job and continue running these steps in parallel.
    10. +
    +
    + +
    +

    Finish Job

    + +
    +
    Input
    +
    job, a job
    +
    Output
    +
    none
    +
    +
      +
    1. Assert: the top element in the job queue is job.
    2. +
    3. Pop the top element from the job queue.
    4. +
    5. If the job queue is not empty, invoke Run Job with the top element of the job queue.
    6. +
    +
    + +
    +

    Resolve Job Promise

    + +
    +
    Input
    +
    job, a job
    +
    value, any
    +
    Output
    +
    none
    +
    +
      +
    1. Resolve job's promise with value.
    2. +
    3. For each promise in job's list of equivalent job promises: +
        +
      1. Resolve promise with value.
      2. +
      +
    4. +
    +
    + +
    +

    Reject Job Promise

    + +
    +
    Input
    +
    job, a job
    +
    reason, an exception
    +
    Output
    +
    none
    +
    +
      +
    1. Reject job's promise with reason.
    2. +
    3. For each promise in job's list of equivalent job promises: +
        +
      1. Reject promise with reason.
      2. +
      +
    4. +
    +
    + +
    +

    Register

    + +
    +
    Input
    +
    job, a job
    +
    Output
    +
    promise, a promise
    +
    +
      +
    1. If the result of running Is origin potentially trustworthy with the origin of job's script url as the argument is Not Trusted, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    2. +
    3. If the origin of job's script url is not job's client's origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    4. +
    5. If the origin of job's scope url is not job's client's origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    6. +
    7. Let registration be the result of running the Get Registration algorithm passing job's scope url as the argument.
    8. +
    9. If registration is not null, then: +
        +
      1. If registration's uninstalling flag is set, unset it.
      2. +
      3. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
      4. +
      5. If newestWorker is not null and job's script url equals newestWorker's script url, then: +
          +
        1. If newestWorker is an active worker, then: +
            +
          1. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
          2. +
          3. Invoke Finish Job with job and abort these steps.
          4. +
          +
        2. +
        +
      6. +
      +
    10. +
    11. Else: +
        +
      1. Invoke Set Registration algorithm passing job's scope url as its argument.
      2. +
      +
    12. +
    13. Invoke Update algorithm, or its equivalent, passing job as the argument.
    14. +
    +
    + +
    +

    Update

    + +
    +
    Input
    +
    job, a job
    +
    Output
    +
    none
    +
    +
      +
    1. Let registration be the result of running the Get Registration algorithm passing job's scope url as the argument.
    2. +
    3. If registration is null or registration's uninstalling flag is set, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    4. +
    5. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument.
    6. +
    7. If job's job type is update, and newestWorker's script url is not job's script url, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    8. +
    9. Let r be the associated request of the result of invoking the initial value of {{Request}} as constructor with job's serialized script url. If this throws an exception, then: +
        +
      1. Invoke Reject Job Promise with job and the exception.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    10. +
    11. Set r's initiator to "" and destination to "serviceworker".
    12. +
    13. Set r's client to job's client.
    14. +
    15. Append `Service-Worker`/`script` to r's header list. +

      See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.

      +
    16. +
    17. Set r's skip service worker flag, r's synchronous flag, and r's redirect mode to "error".
    18. +
    19. If newestWorker is not null and registration's last update check time is not null, then: +
        +
      1. If the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, or force bypass cache flag is set, set r's cache mode to "reload".
      2. +
      +

      Even if the cache mode is not set to "reload", the user agent obeys Cache-Control header's max-age value in the network layer to determine if it should bypass the browser cache.

      +
    20. +
    21. Let response be the result of running fetch using r.
    22. +
    23. If response is a network error or response's status is not in the range 200 to 299, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    24. +
    25. Extract a MIME type from the response's header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    26. +
    27. Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response's header list. +

      See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.

      +
    28. +
    29. If serviceWorkerAllowed is failure, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    30. +
    31. Let scopeURL be registration's scope url.
    32. +
    33. Let maxScopeString be null.
    34. +
    35. If serviceWorkerAllowed is null, then: +
        +
      1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script's file name, in job's script url's path (including empty strings), separated from each other by "/".
      2. +
      +
    36. +
    37. Else: +
        +
      1. Let maxScope be the result of parsing serviceWorkerAllowed with job's script url.
      2. +
      3. Set maxScopeString to "/" concatenated with the strings in maxScope's path (including empty strings), separated from each other by "/".
      4. +
      +
    38. +
    39. Let scopeString be "/" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/".
    40. +
    41. If scopeString starts with maxScopeString, do nothing.
    42. +
    43. Else: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      4. +
      5. Invoke Finish Job with job and abort these steps.
      6. +
      +
    44. +
    45. If response's cache state is not "local", set registration's last update check time to the current time.
    46. +
    47. If newestWorker is not null, newestWorker's script url equals job's script url with the exclude fragments flag set, and response is a byte-for-byte match with the script resource of newestWorker, then: +
        +
      1. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    48. +
    49. Else: +
        +
      1. Let worker be a new service worker.
      2. +
      3. Generate a unique opaque string and set worker's id to the value.
      4. +
      5. Set worker's script url to job's script url, worker's script resource to the script resource retrieved from the fetched response.
      6. +
      7. Invoke Run Service Worker algorithm with worker as the argument.
      8. +
      9. If an uncaught runtime script error occurs during the above step, then: +
          +
        1. Invoke Reject Job Promise with job and a TypeError.
        2. +
        3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
        4. +
        5. Invoke Finish Job with job and abort these steps.
        6. +
        +
      10. +
      +
    50. +
    51. Invoke Install algorithm, or its equivalent, with job, worker, and registration as its arguments.
    52. +
    +
    + +
    +

    Soft Update

    + +

    The user agent may call this as often as it likes to check for updates.

    + +
    +
    Input
    +
    registration, a service worker registration
    +
    force bypass cache flag, an optional flag unset by default
    +

    Implementers may use the force bypass cache flag to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs.

    +
    Output
    +
    None
    +
    +
      +
    1. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
    2. +
    3. If newestWorker is null, abort these steps.
    4. +
    5. Let job be the result of running Create Job with update, registration's scope url, newestWorker's script url, a new promise, and null.
    6. +
    7. Set job's force bypass cache flag if its force bypass cache flag is set.
    8. +
    9. Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job.
      2. +
      +
    10. +
    +
    + +
    +

    Install

    + +
    +
    Input
    +
    job, a job
    +
    worker, a service worker
    +
    registration, a service worker registration
    +
    Output
    +
    none
    +
    +
      +
    1. Let installFailed be false.
    2. +
    3. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
    4. +
    5. Set registration's installing worker to worker.
    6. +
    7. Run the Update State algorithm passing registration's installing worker and installing as the arguments.
    8. +
    9. Assert: job's promise is not null.
    10. +
    11. Invoke Resolve Job Promise with job and the {{ServiceWorkerRegistration}} object which represents registration.
    12. +
    13. Queue a task to fire a simple event named updatefound at all the {{ServiceWorkerRegistration}} objects for all the service worker clients whose creation url matches registration's scope url and all the service workers whose containing service worker registration is registration.
    14. +
    15. Let installingWorker be registration's installing worker.
    16. +
    17. Invoke Run Service Worker algorithm with installingWorker as the argument.
    18. +
    19. Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the {{ExtendableEvent}} interface, with the event type install, which does not bubble, is not cancelable, and has no default action.
      2. +
      3. Dispatch e at installingWorker's environment settings object's global object globalObject.
      4. +
      5. Let extendLifetimePromises be an empty array.
      6. +
      7. For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling.
          2. +
          3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
          4. +
          5. Set registration's installing worker to null.
          6. +
          7. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
          8. +
          9. Invoke Finish Job with job and abort these steps.
          10. +
          +
        2. +
        3. Let eventObject be the first argument passed to this event listener.
        4. +
        5. Append eventObject's extend lifetime promises to extendLifetimePromises.
        6. +
        +
      8. +
      9. Let p be waiting for all of extendLifetimePromises.
      10. +
      11. Run the following substeps in parallel: +
          +
        1. Wait until p settles.
        2. +
        3. If p rejected, set installFailed to true.
        4. +
        5. Else if p resolved with a value, do nothing.
        6. +
        +
      12. +
      +
    20. +

      If task is discarded or the script has been aborted by the termination of installingWorker, set installFailed to true.

      +
    21. Wait for task to have executed or been discarded.
    22. +
    23. If installFailed is true, then: +
        +
      1. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      2. +
      3. Set registration's installing worker to null.
      4. +
      5. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument.
      6. +
      7. Invoke Finish Job with job and abort these steps.
      8. +
      +
    24. +
    25. Set registration's installing worker's imported scripts updated flag.
    26. +
    27. If registration's waiting worker is not null, then: +
        +
      1. Terminate registration's waiting worker.
      2. +
      3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
      4. +
      5. The user agent may abort in-flight requests triggered by registration's waiting worker.
      6. +
      +
    28. +
    29. Set registration's waiting worker to registration's installing worker.
    30. +
    31. Set registration's installing worker to null.
    32. +
    33. Run the Update State algorithm passing registration's waiting worker and installed as the arguments.
    34. +
    35. If registration's waiting worker's skip waiting flag is set, then: +
        +
      1. Run Activate algorithm, or its equivalent, passing registration as the argument.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    36. +
    37. Invoke Finish Job with job.
    38. +
    39. Wait for all the tasks queued by Update State invoked in this algorithm have executed.
    40. +
    41. Wait until no service worker client is using registration or registration's waiting worker's skip waiting flag is set.
    42. +
    43. If registration's waiting worker waitingWorker is not null and waitingWorker's skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument.
    44. +
    +
    + +
    +

    Activate

    + +
    +
    Input
    +
    registration, a service worker registration
    +
    Output
    +
    None
    +
    +
      +
    1. Let activatingWorker be registration's waiting worker.
    2. +
    3. Let exitingWorker be registration's active worker.
    4. +
    5. If activatingWorker is null, abort these steps.
    6. +
    7. If exitingWorker is not null, then: +
        +
      1. Wait for exitingWorker to finish handling any in-progress requests. +
      2. +
      3. Terminate exitingWorker.
      4. +
      5. Run the Update State algorithm passing exitingWorker and redundant as the arguments.
      6. +
      +
    8. +
    9. Set registration's active worker to activatingWorker.
    10. +
    11. Set registration's waiting worker to null.
    12. +
    13. Run the Update State algorithm passing registration's active worker and activating as the arguments. +

      Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated.

      +
    14. +
    15. For each service worker client client whose creation url matches registration's scope url: +
        +
      1. If client is a window client, unassociate client's responsible document from its application cache, if it has one.
      2. +
      3. Else if client is a shared worker client, unassociate client's global object from its application cache, if it has one.
      4. +
      +

      Resources will now use the service worker registration instead of the existing application cache.

      +
    16. +
    17. For each service worker client client who is using registration: +
        +
      1. Set client's active worker to registration's active worker.
      2. +
      3. Invoke Notify Controller Change algorithm with client as the argument.
      4. +
      +
    18. +
    19. Let activeWorker be registration's active worker.
    20. +
    21. Invoke Run Service Worker algorithm with activeWorker as the argument.
    22. +
    23. Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the {{ExtendableEvent}} interface, with the event type activate, which does not bubble, is not cancelable, and has no default action.
      2. +
      3. Dispatch e at activeWorker's environment settings object's global object.
      4. +
      5. Let extendLifetimePromises be an empty array.
      6. +
      7. For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, report the error for the script per the runtime script errors handling.
        2. +
        3. Let eventObject be the first argument passed to this event listener.
        4. +
        5. Append eventObject's extend lifetime promises to extendLifetimePromises.
        6. +
        +
      8. +
      9. Let p be waiting for all of extendLifetimePromises.
      10. +
      +
    24. +
    25. Wait for task to have executed and p defined in task has settled, or task to have been discarded or the script to have been aborted by the termination of activeWorker.
    26. +
    27. Run the Update State algorithm passing registration's active worker and activated as the arguments.
    28. +
    +
    + +
    +

    Run Service Worker

    + +
    +
    Input
    +
    serviceWorker, a service worker
    +
    Output
    +
    None
    +
    +
      +
    1. Assert: serviceWorker has the script resource successfully fetched against its script url.
    2. +
    3. If serviceWorker is already running, abort these steps.
    4. +
    5. Let workerGlobalScope be a new {{ServiceWorkerGlobalScope}} object.
    6. +
    7. Let workerEventLoop be a newly created event loop.
    8. +
    9. If serviceWorker is an active worker, and there are any tasks queued in serviceWorker's containing service worker registration's task queues, queue them to serviceWorker's event loop's task queues in the same order using their original task sources.
    10. +
    11. Let settingsObject be a new environment settings object whose algorithms are defined as follows: +
      +
      The script execution environments
      +
      When the environment settings object is created, for each language supported by the user agent, create an appropriate execution environment as defined by the relevant specification.
      +
      When a script execution environment is needed, return the appropriate one from those created when the environment settings object was created.
      +
      The global object
      +
      Return workerGlobalScope.
      +
      The responsible event loop
      +
      Return workerEventLoop.
      +
      The referrer source
      +
      Return serviceWorker's script url.
      +
      The API URL character encoding
      +
      Return UTF-8.
      +
      The API base URL
      +
      Return serviceWorker's script url.
      +
      The origin and effective script origin
      +
      Return its registering service worker client's origin.
      +
      +
    12. +
    13. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context.
    14. +
    15. Let source be the result of running the UTF-8 decode algorithm on serviceWorker's script resource scriptResource.
    16. +
    17. Let language be JavaScript.
    18. +
    19. In the newly created execution environment, create a JavaScript global environment whose global object is workerGlobalScope. (The JavaScript global environment whose global object is a {{ServiceWorkerGlobalScope}} object is defined as the service worker environment, which is a type of worker environments.)
    20. +
    21. Let script be a new script.
    22. +
    23. Obtain the appropriate script execution environment for the scripting language language from settingsObject.
    24. +
    25. Parse/compile/initialize source using that script execution environment, as appropriate for language, and thus obtain a code entry-point. If the script was not compiled successfully, let the code entry-point be a no-op script, and act as if a corresponding uncaught script error had occurred.
    26. +
    27. Let script's settings object be settingsObject.
    28. +
    29. Jump to the script's code entry-point, and let that run until it either returns, fails to catch an exception, or gets aborted by the kill a worker or Terminate Service Worker algorithms.
    30. +
    31. If scriptResource's has ever been evaluated flag is unset, then: +
        +
      1. Set workerGlobalScope's associated service worker's set of event types to handle to the set of event types created from settingsObject's global object's associated list of event listeners' event types. +

        If the global object's associated list of event listeners does not have any event listener added at this moment, the service worker's set of event types to handle is set to an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script.

        +
      2. +
      3. Set scriptResource's has ever been evaluated flag.
      4. +
      +
    32. +
    33. Run the responsible event loop specified by settingsObject until it is destroyed.
    34. +
    35. Empty workerGlobalScope's list of active timers.
    36. +
    +
    + +
    +

    Terminate Service Worker

    + +
    +
    Input
    +
    serviceWorker, a service worker
    +
    Output
    +
    None
    +
    +
      +
    1. If serviceWorker is not running, abort these steps.
    2. +
    3. Let serviceWorkerGlobalScope be serviceWorker environment settings object's global object.
    4. +
    5. Set serviceWorkerGlobalScope's closing flag to true.
    6. +
    7. If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in serviceWorkerGlobalScope's event loop's task queues, queue them to serviceWorker's containing service worker registration's corresponding task queues in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from serviceWorkerGlobalScope's event loop's task queues without processing them. +

      This effectively means that the fetch events and the other functional events such as push events are backed up by the registration's task queues while the other tasks including message events are discarded.

      +
    8. +
    9. Abort the script currently running in serviceWorker.
    10. +
    +
    + +
    +

    Handle Fetch

    + +

    The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

    + +
    +
    Input
    +
    request, a request
    +
    Output
    +
    response, a response
    +
    +
      +
    1. Let handleFetchFailed be false.
    2. +
    3. Let respondWithEntered be false.
    4. +
    5. Let eventCanceled be false.
    6. +
    7. Let r be a new {{Request}} object associated with request.
    8. +
    9. Let headersObject be r's {{Request/headers}} attribute value.
    10. +
    11. Set headersObject's guard to immutable.
    12. +
    13. Let response be null.
    14. +
    15. Let registration be null.
    16. +
    17. Let client be the service worker client that corresponds to request's client.
    18. +
    19. Assert: request's destination is not "serviceworker".
    20. +
    21. If request is a potential-navigation-or-subresource request, then: +
        +
      1. Return null.
      2. +
      +
    22. +
    23. Else if request is a non-subresource request, then: +

      If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration.

      +
        +
      1. If client is not a secure context, return null.
      2. +
      3. If request is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null.
      4. +
      5. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing request's url as the argument.
      6. +
      7. If registration is null or registration's active worker is null, return null.
      8. +
      9. Set client's active worker to registration's active worker.
      10. +
      +

      From this point, the service worker client starts to use its active worker's containing service worker registration.

      +
    24. +
    25. Else if request is a subresource request, then: +
        +
      1. If client's active worker is non-null, set registration to client's active worker's containing service worker registration.
      2. +
      3. Else, return null.
      4. +
      +
    26. +
    27. Let activeWorker be registration's active worker.
    28. +
    29. If activeWorker's set of event types to handle does not contain fetch, return null. +

      To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.

      +
    30. +
    31. If activeWorker's state is activating, wait for activeWorker's state to become activated.
    32. +
    33. Invoke Run Service Worker algorithm with activeWorker as the argument.
    34. +
    35. Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the {{FetchEvent}} interface, with the event type fetch, which does not bubble and has no default action.
      2. +
      3. Let the request attribute of e be initialized to r.
      4. +
      5. Let the clientId attribute of e be initialized to client's id if request is not a non-subresource request, and to null otherwise.
      6. +
      7. Let the isReload attribute of e be initialized to true if request's client is a window client and the event was dispatched with the user's intention for the page reload, and false otherwise.
      8. +
      9. Dispatch e at activeWorker's environment settings object's global object.
      10. +
      11. For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling.
          2. +
          3. Abort these steps.
          4. +
          +
        2. +
        3. Let event be the event for which this event listener was invoked.
        4. +
        5. If event's respond-with entered flag is set, set respondWithEntered to true.
        6. +
        7. If event's wait to respond flag is set, then: +
            +
          1. Wait until event's wait to respond flag is unset.
          2. +
          3. If event's respond-with error flag is set, set handleFetchFailed to true.
          4. +
          5. Else, set response to event's potential response.
          6. +
          +
        8. +
        9. If event's canceled flag is set, set eventCanceled to true.
        10. +
        +
      12. +
      +

      If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

      +

      The task must use activeWorker's event loop and the handle fetch task source.

      +
    36. +
    37. Wait for task to have executed or been discarded.
    38. +
    39. If respondWithEntered is false, then: +
        +
      1. If eventCanceled is true, return a network error and continue running these substeps in parallel.
      2. +
      3. Else, return null and continue running these substeps in parallel.
      4. +
      5. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
      6. +
      7. Abort these steps.
      8. +
      +
    40. +
    41. If handleFetchFailed is true, then: +
        +
      1. Return a network error and continue running these substeps in parallel.
      2. +
      3. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
      4. +
      +
    42. +
    43. Else: +
        +
      1. Return response and continue running these substeps in parallel.
      2. +
      3. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
      4. +
      +
    44. +
    +
    + +
    +

    Handle Functional Event

    + +
    +
    Input
    +
    registration, a service worker registration
    +
    callbackSteps, an algorithm
    +
    Output
    +
    None
    +
    +
      +
    1. Assert: a Record with the \[[value]] equals to registration is contained in scope to registration map.
    2. +
    3. Assert: registration's active worker is not null.
    4. +
    5. Let activeWorker be registration's active worker.
    6. +
    7. If activeWorker's set of event types to handle does not contain the event type for this functional event, return. +

      To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution.

      +
    8. +
    9. If activeWorker's state is activating, wait for activeWorker's state to become activated.
    10. +
    11. Invoke Run Service Worker algorithm with activeWorker as the argument.
    12. +
    13. Queue a task task to invoke callbackSteps with activeWorker's environment settings object's global object as its argument. +

      The task must use activeWorker's event loop and the handle functional event task source.

      +
    14. +
    15. Wait for task to have executed or been discarded.
    16. +
    17. If the time difference in seconds calculated by the current time minus registration's last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration.
    18. +
    +
    + +
    +

    Handle Service Worker Client Unload

    + +

    The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

    + +
    +
    Input
    +
    client, a service worker client
    +
    Output
    +
    None
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. Let registration be the service worker registration used by client.
    4. +
    5. If registration is null, abort these steps.
    6. +
    7. If any other service worker client is using registration, abort these steps.
    8. +
    9. If registration's uninstalling flag is set, invoke Clear Registration algorithm passing registration as its argument and abort these steps.
    10. +
    11. If registration's waiting worker is not null, run Activate algorithm, or its equivalent, with registration as the argument.
    12. +
    +
    + +
    +

    Handle User Agent Shutdown

    + +
    +
    Input
    +
    None
    +
    Output
    +
    None
    +
    +
      +
    1. For each Record {\[[key]], \[[value]]} entry of its scope to registration map: +
        +
      1. Let registration be entry.\[[value]].
      2. +
      3. If registration's installing worker installingWorker is not null, then: +
          +
        1. If the result of running Get Newest Worker with registration is installingWorker, invoke Clear Registration with registration and continue to the next iteration of the loop.
        2. +
        3. Else, set registration's installing worker to null.
        4. +
        +
      4. +
      5. If registration's waiting worker is not null, run the following substep in parallel: +
          +
        1. Invoke Activate with registration.
        2. +
        +
      6. +
      +
    2. +
    +
    + +
    +

    Unregister

    + +
    +
    Input
    +
    job, a job
    +
    Output
    +
    none
    +
    +
      +
    1. If the origin of job's scope url is not job's client's origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "{{SecurityError}}" exception.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    2. +
    3. Let registration be the result of running Get Registration algorithm passing job's scope url as the argument.
    4. +
    5. If registration is null, then: +
        +
      1. Invoke Resolve Job Promise with job and false.
      2. +
      3. Invoke Finish Job with job and abort these steps.
      4. +
      +
    6. +
    7. Set registration's uninstalling flag.
    8. +
    9. Invoke Resolve Job Promise with job and true.
    10. +
    11. If no service worker client is using registration, then: +
        +
      1. If registration's uninstalling flag is unset, invoke Finish Job with job and abort these steps.
      2. +
      3. Invoke Clear Registration algorithm passing registration as its argument.
      4. +
      +

      When the registration is being used for a client, the deletion of the registration is handled by the Handle Service Worker Client Unload algorithm.

      +
    12. +
    13. Invoke Finish Job with job.
    14. +
    +
    + +
    +

    Set Registration

    + +
    +
    Input
    +
    scope, a URL
    +
    Output
    +
    registration, a service worker registration
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. Let scopeString be serialized scope with the exclude fragment flag set.
    4. +
    5. Let registration be a new service worker registration whose scope url is set to scope.
    6. +
    7. Set a newly-created Record {\[[key]]: scopeString, \[[value]]: registration} to scope to registration map.
    8. +
    9. Return registration.
    10. +
    +
    + +
    +

    Clear Registration

    + +
    +
    Input
    +
    registration, a service worker registration
    +
    Output
    +
    None
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. If registration's installing worker is not null, then: +
        +
      1. Terminate registration's installing worker.
      2. +
      3. Run the Update State algorithm passing registration's installing worker and redundant as the arguments.
      4. +
      5. Set registration's installing worker to null.
      6. +
      7. The user agent may abort in-flight requests triggered by registration's installing worker.
      8. +
      +
    4. +
    5. If registration's waiting worker is not null, then: +
        +
      1. Terminate registration's waiting worker.
      2. +
      3. Run the Update State algorithm passing registration's waiting worker and redundant as the arguments.
      4. +
      5. Set registration's waiting worker to null.
      6. +
      7. The user agent may abort in-flight requests triggered by registration's waiting worker.
      8. +
      +
    6. +
    7. If registration's active worker is not null, then: +
        +
      1. Terminate registration's active worker.
      2. +
      3. Run the Update State algorithm passing registration's active worker and redundant as the arguments.
      4. +
      5. Set registration's active worker to null.
      6. +
      7. The user agent may abort in-flight requests triggered by registration's active worker.
      8. +
      +
    8. +
    9. Delete a Record {\[[key]], \[[value]]} entry from scope to registration map where registration's scope url is the result of parsing entry.\[[key]].
    10. +
    +
    + +
    +

    Update State

    + +
    +
    Input
    +
    worker, a service worker
    +
    state, a service worker's state
    +
    Output
    +
    None
    +
    +
      +
    1. Set worker's state to state.
    2. +
    3. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker.
    4. +
    5. For each serviceWorker in serviceWorkers: +
        +
      1. Queue a task to fire a simple event named statechange at serviceWorker.
      2. +
      +

      The task must use serviceWorker's relevant settings object's responsible event loop and the DOM manipulation task source.

      +
    6. +
    +
    + +
    +

    Notify Controller Change

    + +
    +
    Input
    +
    client, a service worker client
    +
    Output
    +
    None
    +
    +
      +
    1. Assert: client is not null.
    2. +
    3. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with.
    4. +
    +

    The task must use client's responsible event loop and the DOM manipulation task source.

    +
    + +
    +

    Match Service Worker Registration

    + +
    +
    Input
    +
    clientURL, a URL
    +
    Output
    +
    registration, a service worker registration
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. Let clientURLString be serialized clientURL.
    4. +
    5. Let matchingScope be the empty string.
    6. +
    7. Set matchingScope to the longest \[[key]] in scope to registration map which the value of clientURLString starts with, if it exists. +

      The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix").

      +
    8. +
    9. Let parsedMatchingScope be null.
    10. +
    11. If matchingScope is not the empty string, set parsedMatchingScope to the result of parsing matchingScope.
    12. +
    13. Let registration be the result of running Get Registration algorithm passing parsedMatchingScope as the argument.
    14. +
    15. If registration is not null and registration's uninstalling flag is set, return null.
    16. +
    17. Return registration.
    18. +
    +
    + +
    +

    Get Registration

    + +
    +
    Input
    +
    scope, a URL
    +
    Output
    +
    registration, a service worker registration
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. Let scopeString be the empty string.
    4. +
    5. If scope is not null, set scopeString to serialized scope with the exclude fragment flag set.
    6. +
    7. Let registration be null.
    8. +
    9. For each Record {\[[key]], \[[value]]} entry of its scope to registration map: +
        +
      1. If scopeString matches entry.\[[key]], set registration to entry.\[[value]].
      2. +
      +
    10. +
    11. Return registration.
    12. +
    +
    + +
    +

    Get Newest Worker

    + +
    +
    Input
    +
    registration, a service worker registration
    +
    Output
    +
    worker, a service worker
    +
    +
      +
    1. Run the following steps atomically.
    2. +
    3. Let newestWorker be null.
    4. +
    5. If registration's installing worker is not null, set newestWorker to registration's installing worker.
    6. +
    7. Else if registration's waiting worker is not null, set newestWorker to registration's waiting worker.
    8. +
    9. Else if registration's active worker is not null, set newestWorker to registration's active worker.
    10. +
    11. Return newestWorker.
    12. +
    +
    + +
    +

    Create Client

    + +
    +
    Input
    +
    client, a service worker client
    +
    Output
    +
    clientObject, a {{Client}} object
    +
    +
      +
    1. Let clientObject be a new {{Client}} object.
    2. +
    3. Set clientObject's service worker client to client.
    4. +
    5. Return clientObject.
    6. +
    +
    + +
    +

    Create Window Client

    + +
    +
    Input
    +
    client, a service worker client
    +
    visibilityState, a string
    +
    focusState, a boolean
    +
    Output
    +
    windowClient, a {{WindowClient}} object
    +
    +
      +
    1. Let windowClient be a new {{WindowClient}} object.
    2. +
    3. Set windowClient's service worker client to client.
    4. +
    5. Set windowClient's visibility state to visibilityState.
    6. +
    7. Set windowClient's focus state to focusState.
    8. +
    9. Return windowClient.
    10. +
    +
    + +
    +

    Query Cache

    + +
    +
    Input
    +
    request, a {{Request}} object
    +
    options, a {{CacheQueryOptions}} object, optional
    +
    targetStorage, an array that has [{{Request}}, {{Response}}] pairs as its elements, optional
    +
    Output
    +
    resultArray, an array that has [{{Request}}, {{Response}}] pairs as its elements
    +
    +
      +
    1. Let requestArray be an empty array.
    2. +
    3. Let responseArray be an empty array.
    4. +
    5. Let resultArray be an empty array.
    6. +
    7. If options.{{CacheQueryOptions/ignoreMethod}} is false and request.method is neither "GET" nor "HEAD", return resultArray.
    8. +
    9. Let cachedURL and requestURL be null.
    10. +
    11. Let serializedCachedURL and serializedRequestURL be null.
    12. +
    13. If the optional argument targetStorage is omitted, then: +
        +
      1. For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Set cachedURL to entry.\[[key]]'s associated request's url.
        2. +
        3. Set requestURL to request's associated request's url.
        4. +
        5. If options.ignoreSearch is true, then: +
            +
          1. Set cachedURL's query to the empty string.
          2. +
          3. Set requestURL's query to the empty string.
          4. +
          +
        6. +
        7. Set serializedCachedURL to serialized cachedURL.
        8. +
        9. Set serializedRequestURL to serialized requestURL.
        10. +
        11. If serializedCachedURL matches serializedRequestURL, then: +
            +
          1. Add a copy of entry.\[[key]] to requestArray.
          2. +
          3. Add a copy of entry.\[[value]] to responseArray.
          4. +
          +
        12. +
        +
      2. +
      +
    14. +
    15. Else: +
        +
      1. For each record in targetStorage: +
          +
        1. Set cachedURL to record[0]'s associated request's url.
        2. +
        3. Set requestURL to request's associated request's url.
        4. +
        5. If options.{{CacheQueryOptions/ignoreSearch}} is true, then: +
            +
          1. Set cachedURL's query to the empty string.
          2. +
          3. Set requestURL's query to the empty string.
          4. +
          +
        6. +
        7. Set serializedCachedURL to serialized cachedURL.
        8. +
        9. Set serializedRequestURL to serialized requestURL.
        10. +
        11. If serializedCachedURL matches serializedRequestURL, then: +
            +
          1. Add record[0] to requestArray.
          2. +
          3. Add record[1] to responseArray.
          4. +
          +
        12. +
        +
      2. +
      +
    16. +
    17. For each cachedResponse in responseArray with the index index: +
        +
      1. Let cachedRequest be the indexth element in requestArray.
      2. +
      3. If cachedResponse's response's header list contains no header named `Vary`, or options.{{CacheQueryOptions/ignoreVary}} is true, then: +
          +
        1. Add an array [cachedRequest, cachedResponse] to resultArray.
        2. +
        3. Continue to the next iteration of the loop.
        4. +
        +
      4. +
      5. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header.
      6. +
      7. Let matchFailed be false.
      8. +
      9. For each f in varyHeaders: +
          +
        1. If f matches "*", or the result of running cachedRequest.{{Request/headers}} object's {{Headers/get(name)}} method with f as the argument does not match the result of running request.{{Request/headers}} object's {{Headers/get(name)}} method with f as the argument, then: +
            +
          1. Set matchFailed to true.
          2. +
          3. Break the loop.
          4. +
          +
        2. +
        +
      10. +
      11. If matchFailed is false, add an array [cachedRequest, cachedResponse] to resultArray.
      12. +
      +
    18. +
    19. Return resultArray.
    20. +
    +
    + +
    +

    Batch Cache Operations

    + +
    +
    Input
    +
    operations, an array of {{CacheBatchOperation}} dictionary objects
    +
    Output
    +
    promise, a promise resolves with an array of {{Response}} objects.
    +
    +
      +
    1. Let p be a promise resolved with no value.
    2. +
    3. Return the result of transforming p with a fulfillment handler that performs the following substeps in parallel: +
        +
      1. Let itemsCopy be a new request to response map that is a copy of its context object's request to response map.
      2. +
      3. Let addedRecords be an empty array.
      4. +
      5. Try running the following substeps atomically: +
          +
        1. Let resultArray be an empty array.
        2. +
        3. For each operation in operations with the index index: +
            +
          1. If operation.{{CacheBatchOperation/type}} matches neither "delete" nor "put", throw a TypeError.
          2. +
          3. If operation.{{CacheBatchOperation/type}} matches "delete" and operation.{{CacheBatchOperation/response}} is not null, throw a TypeError.
          4. +
          5. If the result of running Query Cache algorithm passing operation.{{CacheBatchOperation/request}}, operation.{{CacheBatchOperation/options}}, and addedRecords as the arguments is not an empty array, throw an "{{InvalidStateError}}" exception.
          6. +
          7. Let requestResponseArray be the result of running Query Cache algorithm passing operation.{{CacheBatchOperation/request}} and operation.{{CacheBatchOperation/options}} as the arguments.
          8. +
          9. For each requestResponse in requestResponseArray: +
              +
            1. If operation.{{CacheBatchOperation/type}} matches "delete", remove the corresponding fetching record from request to response map.
            2. +
            +
          10. +
          11. If operation.{{CacheBatchOperation/type}} matches "put", then: +
              +
            1. If operation.{{CacheBatchOperation/response}} is null, throw a TypeError.
            2. +
            3. Let r be operation.{{CacheBatchOperation/request}}'s associated request.
            4. +
            5. If r's url's scheme is not one of "http" and "https", throw a TypeError.
            6. +
            7. If r's method is not `GET`, throw a TypeError.
            8. +
            9. If operation.{{CacheBatchOperation/options}} is not null, throw a TypeError.
            10. +
            11. If there exists a corresponding fetching record fetchingRecord for operation.{{CacheBatchOperation/request}} and operation.{{CacheBatchOperation/response}} in request to response map, set fetchingRecord.\[[value]] to operation.{{CacheBatchOperation/response}}.
            12. +
            13. Else, set a newly-created fetching record {\[[key]]: operation.{{CacheBatchOperation/request}}, \[[value]]: operation.{{CacheBatchOperation/response}}} to request to response map. +

              The cache commit is allowed as long as the response's headers are available.

              +
            14. +
            15. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "{{QuotaExceededError}}" exception.
            16. +
            17. Add an array [operation.request, operation.response] to addedRecords.
            18. +
            +
          12. +
          13. Add operation.response to resultArray.
          14. +
          +
        4. +
        5. Return resultArray.
        6. +
        +
      6. +
      7. And then, if an exception was thrown, then: +
          +
        1. Set the context object's request to response map to itemsCopy.
        2. +
        3. Throw the exception
        4. +
        +
      8. +
      +
    4. +
    +
    +
    + +
    +

    Appendix B: Extended HTTP headers

    + +
    +

    Service Worker Script Request

    + +

    An HTTP request to fetch a service worker's script resource will include the following header:

    + +
    +
    `Service-Worker`
    +
    Indicates this request is a service worker's script resource request. +

    This header helps administrators log the requests and detect threats.

    +
    +
    +
    + +
    +

    Service Worker Script Response

    + +

    An HTTP response to a service worker's script resource request can include the following header:

    + +
    +
    `Service-Worker-Allowed`
    +
    Indicates the user agent will override the path restriction, which limits the maximum allowed scope url that the script can control, to the given value. +

    The value is a URL. If a relative URL is given, it is parsed against the script's URL.

    +
    +
    + +
    + Default scope: + +
    +// Maximum allowed scope defaults to the path the script sits in
    +// "/js" in this example
    +navigator.serviceWorker.register("/js/sw.js").then(function() {
    +  console.log("Install succeeded with the default scope '/js'.");
    +});
    +      
    +
    + +
    + Upper path without Service-Worker-Allowed header: + +
    +// Set the scope to an upper path of the script location
    +// Response has no Service-Worker-Allowed header
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed due to the path restriction violation.");
    +});
    +      
    +
    + +
    + Upper path with Service-Worker-Allowed header: + +
    +// Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /"
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(function() {
    +  console.log("Install succeeded as the max allowed scope was overriden to '/'.");
    +});
    +      
    +
    + +
    + A path restriction voliation even with Service-Worker-Allowed header: + +
    +// Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /foo"
    +navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
    +});
    +      
    +
    +
    + +
    +

    Syntax

    + +

    ABNF for the values of the headers used by the service worker's script resource requests and responses:

    + +
    +    Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
    +    
    + +

    The validation of the Service-Worker-Allowed header's values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.

    +
    +
    + +
    +

    Acknowledgements

    + +

    Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

    + +

    Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him.

    + +

    In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref and Jinho Bang.

    + +

    Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

    + +

    The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

    + +

    Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.

    +
    diff --git a/spec/service_worker_1/index.html b/spec/service_worker_1/index.html new file mode 100644 index 00000000..959cfc46 --- /dev/null +++ b/spec/service_worker_1/index.html @@ -0,0 +1,5761 @@ + + + + + Service Workers 1 + + + + + + +
    +

    +

    Service Workers 1

    +

    Editor’s Draft,

    +
    +
    +
    This version: +
    https://slightlyoff.github.io/ServiceWorker/spec/service_worker_1/ +
    Latest version: +
    https://www.w3.org/TR/service-workers/ +
    Feedback: +
    public-webapps@w3.org with subject line “[service-workers] … message topic …” (archives) +
    Issue Tracking: +
    GitHub +
    Inline In Spec +
    Editors: +
    (Google) +
    (Samsung Electronics) +
    (Google) +
    (Google) +
    +
    +
    + +
    +
    +

    Abstract

    +
    +

    This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.

    +

    The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.

    +

    The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.

    +
    +

    Status of this document

    +
    +

    This is a public copy of the editors’ draft. + It is provided for discussion only and may change at any moment. + Its publication here does not imply endorsement of its contents by W3C. + Don’t cite this document other than as work in progress.

    +

    Changes to this document may be tracked at https://github.com/slightlyoff/ServiceWorker.

    +

    The (archived) public mailing list public-webapps@w3.org (see instructions) + is preferred for discussion of this specification. + When sending e-mail, + please put the text “service-workers” in the subject, + preferably like this: + “[service-workers] …summary of comment…

    +

    This document was produced by the Web Platform Working Group.

    +

    This document was produced by a group operating under + the 5 February 2004 W3C Patent Policy. + W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; + that page also includes instructions for disclosing a patent. + An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

    +

    This document is governed by the 1 September 2015 W3C Process Document.

    +

    +
    +
    + +
    +
    +

    1. Motivations

    +

    This section is non-normative.

    +

    Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks.

    +

    The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.

    +

    Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the service worker is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep service workers responsive in the face of a single-threaded execution model. As a result, APIs exposed by service workers are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading.

    +

    Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the service worker is that errors should always be recoverable. Many details of the update process of service workers are designed to avoid these hazards.

    +

    Service workers are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, service workers bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. Service workers may be started by user agents without an attached document and may be killed by the user agent at nearly any time. Conceptually, service workers can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that service workers may be started and killed many times a second.

    +

    Service workers are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

    +
    +
    +

    2. Model

    +
    +

    2.1. Service Worker

    +

    A service worker#dfn-service-workerReferenced in:1. Motivations (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)2.1. Service Worker (2) (3) (4) (5) (6) (7) (8) (9) (10) (11)2.1.1. Lifetime (2)2.2. Service Worker Registration (2) (3) (4)2.5. Task sources (2) (3)2.6. User Agent Shutdown3.1. ServiceWorker (2) (3) (4)3.1.1. scriptURL3.1.2. state (2) (3) (4) (5) (6) (7) (8) (9)3.1.3. postMessage(message, transfer)3.2.1. installing3.2.2. waiting3.2.3. active3.4. ServiceWorkerContainer3.4.1. controller3.5. ServiceWorkerMessageEvent (2)3.5.2. event.origin3.5.4. event.source3.6. Events (2) (3)4.1. ServiceWorkerGlobalScope (2) (3) (4)4.1.3. skipWaiting() (2) (3) (4)4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f) (2) (3) (4) (5)4.5. FetchEvent (2)4.6. ExtendableMessageEvent (2)5.2. Understanding Cache Lifetimes (2)6.1. Secure Context (2) (3) (4) (5)6.2. Content Security Policy6.3.1. Origin restriction (2) (3)6.4. Cross-Origin Resources and CORS6.5. Implementer Concerns (2) (3)6.6. Privacy (2)7. Storage Considerations (2)8. Extensibility8.4. Request Functional Event DispatchUpdateInstall (2)Run Service WorkerTerminate Service WorkerHandle FetchUpdate State (2)Get Newest WorkerService Worker Script Request (2)Service Worker Script ResponseSyntax is a type of web worker. A service worker executes in the registering service worker client’s origin.

    +

    A service worker has an associated state#dfn-stateReferenced in:2.2. Service Worker Registration (2) (3)3.1. ServiceWorker3.1.2. state3.2.5. update()4.1.3. skipWaiting()4.4.1. event.waitUntil(f) (2) (3)Handle Fetch (2)Handle Functional Event (2)Update State (2), which is one of parsed, installing, installed, activating, activated, and redundant. It is initially parsed.

    +

    A service worker has an associated script url#dfn-script-urlReferenced in:3.1.1. scriptURL3.2.5. update()RegisterUpdate (2) (3)Soft UpdateRun Service Worker (2) (3) (a URL).

    +

    A service worker has an associated containing service worker registration#dfn-containing-service-worker-registrationReferenced in:2.1. Service Worker2.4. Selection and Use3.2.6. unregister()4.1.2. registration4.1.3. skipWaiting() (2) (3)4.3.4. claim()4.7. Events (2)InstallRun Service WorkerTerminate Service WorkerHandle Fetch (2) (a service worker registration), which contains itself.

    +

    A service worker has an associated id#dfn-service-worker-idReferenced in:Update (an opaque string), which uniquely identifies itself during the lifetime of its containing service worker registration.

    +

    A service worker is dispatched a set of lifecycle events#dfn-lifecycle-eventsReferenced in:4.4. ExtendableEvent4.7. Events (2), install and activate, and functional events#dfn-functional-eventsReferenced in:2.5. Task sources3.1.2. state (2)4.4.1. event.waitUntil(f)4.5. FetchEvent4.7. Events8.2. Define Functional Event8.3. Define Event Handler8.4. Request Functional Event Dispatch (2) (3) including fetch.

    +

    A service worker has an associated script resource#dfn-script-resourceReferenced in:2.1. Service Worker6.2. Content Security Policy (2)UpdateRun Service WorkerService Worker Script Request (2)Service Worker Script ResponseSyntax, which represents its own script resource. It is initially set to null. A script resource has an associated has ever been evaluated flag#dfn-has-ever-been-evaluated-flagReferenced in:Run Service Worker (2). It is initially unset.

    +

    A service worker has an associated script resource map#dfn-script-resource-mapReferenced in:6.3.2. importScripts(urls) (2) (3)6.6. Privacy which is a List of the Record {[[key]], [[value]]} where [[key]] is a URL and [[value]] is a script resource.

    +

    A service worker has an associated skip waiting flag#dfn-skip-waiting-flagReferenced in:3.6. Events4.1.3. skipWaiting()Install (2) (3). Unless stated otherwise it is unset.

    +

    A service worker has an associated imported scripts updated flag#dfn-imported-scripts-updated-flagReferenced in:6.3.2. importScripts(urls) (2)Install. It is initially unset.

    +

    A service worker has an associated set of event types to handle#dfn-set-of-event-types-to-handleReferenced in:Run Service WorkerHandle FetchHandle Functional Event whose element type is an event listener’s event type. It is initially set to null.

    +
    +

    2.1.1. Lifetime

    +

    The lifetime of a service worker is tied to the execution lifetime of events and not references held by service worker clients to the ServiceWorker object.

    +

    A user agent may terminate service workers at any time it:

    +
      +
    • Has no event to handle. +
    • Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events. +
    +
    +
    +
    +

    2.2. Service Worker Registration

    +

    A service worker registration#dfn-service-worker-registrationReferenced in:2.1. Service Worker2.2. Service Worker Registration (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)2.2.1. Lifetime (2) (3) (4)2.4. Selection and Use (2) (3) (4) (5) (6) (7) (8)2.6. User Agent Shutdown (2) (3)3.2. ServiceWorkerRegistration (2) (3)3.2.6. unregister() (2)3.4. ServiceWorkerContainer (2)3.4.2. ready3.4.3. register(scriptURL, options) (2)3.6. Events (2)6.1. Secure Context (2)6.6. Privacy8.1. Define API bound to Service Worker Registration8.4. Request Functional Event DispatchAppendix A: Algorithms (2) (3)Soft UpdateInstallActivateHandle Functional EventHandle Service Worker Client UnloadSet Registration (2)Clear RegistrationMatch Service Worker RegistrationGet RegistrationGet Newest Worker is a tuple of a scope url and a set of service workers, an installing worker, a waiting worker, and an active worker. A user agent may enable many service worker registrations at a single origin so long as the scope url of the service worker registration differs. A service worker registration of an identical scope url when one already exists in the user agent causes the existing service worker registration to be replaced.

    +

    A service worker registration has an associated scope url#dfn-scope-urlReferenced in:2.2. Service Worker Registration (2) (3)2.2.1. Lifetime2.4. Selection and Use3.2.4. scope3.2.5. update()3.2.6. unregister()3.4.3. register(scriptURL, options) (2)Appendix A: Algorithms (2)UpdateSoft UpdateInstallActivateSet RegistrationClear RegistrationService Worker Script Response (a URL).

    +

    A service worker registration has an associated registering script url (a URL).

    +

    A service worker registration has an associated installing worker#dfn-installing-workerReferenced in:2.2. Service Worker Registration2.6. User Agent Shutdown (2)3.1.2. state (2)3.2.1. installing3.6. Events4.4.1. event.waitUntil(f)4.7. EventsInstall (2) (3) (4) (5) (6) (7) (8) (9) (10)Handle User Agent Shutdown (2)Clear Registration (2) (3) (4) (5)Get Newest Worker (2) (a service worker) whose state is installing. It is initially set to null.

    +

    A service worker registration has an associated waiting worker#dfn-waiting-workerReferenced in:2.2. Service Worker Registration2.6. User Agent Shutdown3.1.2. state3.2.2. waiting4.1.3. skipWaiting()4.4.1. event.waitUntil(f) (2)Install (2) (3) (4) (5) (6) (7) (8) (9)Activate (2)Handle Service Worker Client UnloadHandle User Agent ShutdownClear Registration (2) (3) (4) (5)Get Newest Worker (2) (a service worker) whose state is installed. It is initially set to null.

    +

    A service worker registration has an associated active worker#dfn-active-workerReferenced in:2.2. Service Worker Registration (2) (3) (4) (5) (6)2.3. Service Worker Client2.4. Selection and Use (2) (3)2.6. User Agent Shutdown3.1.2. state (2) (3)3.2.3. active3.4.2. ready (2) (3)3.6. Events4.1.3. skipWaiting()4.3.4. claim() (2) (3)4.4.1. event.waitUntil(f)4.7. EventsRegisterActivate (2) (3) (4) (5) (6) (7)Run Service WorkerHandle Fetch (2) (3)Handle Functional Event (2)Clear Registration (2) (3) (4) (5)Get Newest Worker (2) (a service worker) whose state is either activating or activated. It is initially set to null.

    +

    A service worker registration has an associated last update check time#dfn-last-update-check-timeReferenced in:Update (2) (3)Handle Fetch (2) (3)Handle Functional Event. It is initially set to null.

    +

    A service worker registration has an associated uninstalling flag#dfn-uninstalling-flagReferenced in:RegisterUpdateHandle Service Worker Client UnloadUnregister (2)Match Service Worker Registration. It is initially unset.

    +

    A service worker registration has one or more task queues#dfn-service-worker-registration-task-queueReferenced in:2.2. Service Worker Registration (2)Run Service WorkerTerminate Service Worker that back up the tasks from its active worker’s event loop’s corresponding task queues. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker’s tasks to the service worker registration’s task queues when the active worker is terminated and re-queues those tasks to the active worker’s event loop’s corresponding task queues when the active worker spins off. Unlike the task queues owned by event loops, the service worker registration’s task queues are not processed by any event loops in and of itself.

    +
    +

    2.2.1. Lifetime

    +

    A user agent must persistently keep a list of registered service worker registrations unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of service worker registration’s scope url and the corresponding service worker registration. The lifetime of service worker registrations is beyond that of the ServiceWorkerRegistration objects which represent them within the lifetime of their corresponding service worker clients.

    +
    +
    +
    +

    2.3. Service Worker Client

    +

    A service worker client#dfn-service-worker-clientReferenced in:2.1. Service Worker2.1.1. Lifetime2.2.1. Lifetime2.3. Service Worker Client (2) (3) (4) (5) (6)2.4. Selection and Use (2) (3) (4) (5) (6) (7) (8) (9)3.2.6. unregister() (2)3.4. ServiceWorkerContainer3.6. Events (2)4.1. ServiceWorkerGlobalScope4.2. Client4.3.1. get(id)4.3.2. matchAll(options) (2)4.3.4. claim()4.6.2. event.origin6.1. Secure Context (2)6.3.1. Origin restrictionAppendix A: AlgorithmsCreate JobInstall (2)Activate (2)Run Service WorkerHandle Fetch (2)Handle Service Worker Client Unload (2) (3)UnregisterNotify Controller ChangeCreate ClientCreate Window Client is an environment settings object that specifies various settings for its JavaScript global environment.

    +

    A service worker client has an associated active worker#dfn-service-worker-client-active-workerReferenced in:3.2.6. unregister()3.4.1. controller3.6. Events4.2.8. navigate(url)4.3.2. matchAll(options)Handle Fetch (2) (3) (4) (an active worker) which currently controls it. It is initially set to null.

    +

    A service worker client has an associated id#dfn-service-worker-client-idReferenced in:4.2.3. id4.3.1. get(id)Handle Fetch (an opaque string), which uniquely identifies itself during its lifetime. It is initially set to a new unique value when the corresponding environment settings object that it represents is created.

    +

    A service worker client has an associated frame type#dfn-service-worker-client-frame-typeReferenced in:4.2.2. frameType, which is one of auxiliary, top-level, nested, and none. Unless stated otherwise it is none.

    +

    A window client#dfn-window-clientReferenced in:4.2.2. frameType (2) (3)4.3.1. get(id)4.3.2. matchAll(options) (2) (3)ActivateHandle Fetch is a service worker client whose global object is a Window object.

    +

    A dedicated worker client#dfn-dedicatedworker-clientReferenced in:2.3. Service Worker Client4.3.2. matchAll(options) is a service worker client whose global object is a DedicatedWorkerGlobalScope object.

    +

    A shared worker client#dfn-sharedworker-clientReferenced in:2.3. Service Worker Client4.3.2. matchAll(options)Activate is a service worker client whose global object is a SharedWorkerGlobalScope object.

    +

    A worker client#dfn-worker-clientReferenced in:2.4. Selection and UseRun Job is either a dedicated worker client or a shared worker client.

    +
    +
    +

    2.4. Selection and Use

    +

    A service worker client independently selects and uses a service worker registration for its own loading and its subresources. The selection#dfn-service-worker-registration-selectionReferenced in:2.4. Selection and Use (2) (3) of a service worker registration, upon a non-subresource request, is a process of either matching a service worker registration from scope to registration map or inheriting an existing service worker registration from its parent or owner context depending on the request’s url.

    +

    When the request’s url is not local, a service worker client matches a service worker registration from scope to registration map. That is, the service worker client attempts to consult a service worker registration whose scope url matches its creation url.

    +

    When the request’s url is local, if the service worker client’s responsible browsing context is a nested browsing context or the service worker client is a worker client, the service worker client inherits the service worker registration from its parent browsing context’s environment or one of the worker’s Documents' environment, respectively, if it exists.

    +

    If the selection was successful, the selected service worker registration’s active worker starts to control#dfn-controlReferenced in:2.3. Service Worker Client2.4. Selection and Use3.2.6. unregister()3.6. EventsService Worker Script Response the service worker client. Otherwise, the flow returns to fetch where it falls back to the default behavior. When a service worker client is controlled by an active worker, it is considered that the service worker client is using#dfn-useReferenced in:2.4. Selection and Use3.6. Events4.1.3. skipWaiting()InstallActivateHandle FetchHandle Service Worker Client Unload (2)Unregister the active worker’s containing service worker registration.

    +
    +
    +

    2.5. Task sources

    +

    The following additional task sources are used by service workers.

    +
    +
    The handle fetch task source#dfn-handle-fetch-task-sourceReferenced in:2.2. Service Worker RegistrationTerminate Service Worker (2)Handle Fetch +
    This task source is used for dispatching fetch events to service workers. +
    The handle functional event task source#dfn-handle-functional-event-task-sourceReferenced in:2.2. Service Worker RegistrationTerminate Service Worker (2)Handle Functional Event +
    + This task source is used for features that dispatch other functional events, e.g. push events, to service workers. +

    A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. For instance, a user agent may use a different task source for task events from other task sources.

    +
    +
    +
    +

    2.6. User Agent Shutdown

    +

    A user agent must maintain the state of its stored service worker registrations across restarts with the following rules:

    + +

    +

    To attain this, the user agent must invoke Handle User Agent Shutdown when it terminates.

    +
    +
    +
    +

    3. Client Context

    +
    + Bootstrapping with a ServiceWorker: +
    // scope defaults to the path the script sits in
    +// "/" in this example
    +navigator.serviceWorker.register("/serviceworker.js").then(
    +  function(registration) {
    +    console.log("success!");
    +    if (registration.installing) {
    +      registration.installing.postMessage("Howdy from your installing page.");
    +    }
    +  },
    +  function(why) {
    +    console.error("Installing the worker failed!:", why);
    +  });
    +
    +
    +

    3.1. ServiceWorker

    +
    [Exposed=(Window,Worker)]
    +interface ServiceWorker : EventTarget {
    +  readonly attribute USVString scriptURL;
    +  readonly attribute ServiceWorkerState state;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +
    +  // event
    +  attribute EventHandler onstatechange;
    +};
    +ServiceWorker implements AbstractWorker;
    +
    +enum ServiceWorkerState {
    +  "installing",
    +  "installed",
    +  "activating",
    +  "activated",
    +  "redundant"
    +};
    +
    +

    A ServiceWorker#service-worker-interfaceReferenced in:2.1.1. Lifetime3.1. ServiceWorker (2) (3) (4) (5) (6)3.1.3. postMessage(message, transfer)3.1.4. Event handler3.2. ServiceWorkerRegistration (2) (3)3.2.1. installing (2)3.2.2. waiting (2)3.2.3. active (2)3.4. ServiceWorkerContainer3.4.1. controller (2)3.5. ServiceWorkerMessageEvent (2) (3)3.5.4. event.source3.6. Events (2)4.1. ServiceWorkerGlobalScope4.2.4. postMessage(message, transfer)4.6. ExtendableMessageEvent (2)Update State object represents a service worker. Each ServiceWorker object is associated with a service worker. Multiple separate objects implementing the ServiceWorker interface across document environments and worker environments can all be associated with the same service worker simultaneously.

    +

    A ServiceWorker object has an associated ServiceWorkerState object which is itself associated with service worker’s state.

    +
    +

    3.1.1. scriptURL

    +

    The scriptURL#service-worker-url-attributeReferenced in:3.1. ServiceWorker3.1.1. scriptURL attribute must return the service worker’s serialized script url.

    +
    + +

    For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:

    +
    // Script on the page https://example.com/app.html
    +navigator.serviceWorker.register("/service_worker.js", { scope: "/" });
    +

    The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

    +
    +
    +
    +

    3.1.2. state

    +

    The state#service-worker-state-attributeReferenced in:3.1. ServiceWorker3.1.2. state3.1.3. postMessage(message, transfer)3.6. Events attribute must return the value (in ServiceWorkerState#service-worker-state-enumReferenced in:3.1. ServiceWorker (2) (3) enumeration) corresponding to the first matching statement, switching on the service worker’s state:

    +
    +
    installing +
    + "installing" +

    The service worker in this state is considered an installing worker. During this state, event.waitUntil(f) can be called inside the oninstall event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the service worker is not active until all of the core caches are populated.

    +
    installed +
    + "installed" +

    The service worker in this state is considered a waiting worker.

    +
    activating +
    + "activating" +

    The service worker in this state is considered an active worker. During this state, event.waitUntil(f) can be called inside the onactivate event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes activated.

    +
    activated +
    + "activated" +

    The service worker in this state is considered an active worker ready to handle functional events.

    +
    redundant +
    + "redundant" +

    A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.

    +
    +
    +
    +

    3.1.3. postMessage(message, transfer)

    +

    The postMessage(message, transfer)#service-worker-postmessage-methodReferenced in:3.1. ServiceWorker3.1.3. postMessage(message, transfer) method must run these steps or their equivalent:

    +
      +
    1. If the state attribute value of the context object is "redundant", throw an "InvalidStateError" exception and abort these steps. +
    2. Let newPorts be an empty array. +
    3. Let transferMap be an empty association list of Transferable objects to placeholder objects. +
    4. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps. +
      2. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts. +
      +
    5. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps. +
    6. Let serviceWorker be the service worker represented by the context object. +
    7. Invoke Run Service Worker algorithm with serviceWorker as the argument. +
    8. Let destination be the ServiceWorkerGlobalScope object associated with serviceWorker. +
    9. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. Let newOwner be the destination’s environment settings object. +
      2. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts). +
      +
    10. Make newPorts into a read only array. +
    11. + Queue a task that runs the following steps: +
        +
      1. Create an event e that uses the ExtendableMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action. +
      2. Let the data attribute of e be initialized to clonedMessage. +
      3. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object. +
      4. If the global object globalObject specified by the incumbent settings object is a ServiceWorkerGlobalScope object, let the source attribute of e be initialized to a new ServiceWorker object that represents globalObject’s service worker. +
      5. Else if globalObject is a Window object, let the source attribute of e be initialized to a new WindowClient object that represents globalObject’s browsing context. +
      6. Else, let it be initialized to a new Client object that represents globalObject’s worker environment. +
      7. Let the ports attribute of e be initialized to newPorts. +
      8. Dispatch e at destination. +
      +

      The task must use the DOM manipulation task source.

      +
    +
    +
    +

    3.1.4. Event handler

    +

    The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorker interface:

    + + + + + +
    event handler + event handler event type +
    onstatechange#service-worker-onstatechange-attributeReferenced in:3.1. ServiceWorker + statechange +
    +
    +
    +
    +

    3.2. ServiceWorkerRegistration

    +
    [Exposed=(Window,Worker)]
    +interface ServiceWorkerRegistration : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? installing;
    +  [Unforgeable] readonly attribute ServiceWorker? waiting;
    +  [Unforgeable] readonly attribute ServiceWorker? active;
    +
    +  readonly attribute USVString scope;
    +
    +  [NewObject] Promise<void> update();
    +  [NewObject] Promise<boolean> unregister();
    +
    +  // event
    +  attribute EventHandler onupdatefound;
    +};
    +
    +

    A ServiceWorkerRegistration#service-worker-registration-interfaceReferenced in:2.2.1. Lifetime3.2. ServiceWorkerRegistration (2) (3) (4)3.2.7. Event handler3.4. ServiceWorkerContainer (2) (3)3.4.2. ready3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()3.6. Events4.1. ServiceWorkerGlobalScope4.1.2. registration8.1. Define API bound to Service Worker RegistrationRegisterUpdateInstall (2) object represents a service worker registration. Each ServiceWorkerRegistration object is associated with a service worker registration#dfn-service-worker-registration-interface-service-worker-registrationReferenced in:3.2.1. installing3.2.2. waiting3.2.3. active3.2.4. scope3.2.5. update()3.2.6. unregister()3.6. Events (a service worker registration). Multiple separate objects implementing the ServiceWorkerRegistration interface across document environments and worker environments can all be associated with the same service worker registration simultaneously.

    +
    + +

    installing#service-worker-registration-installing-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.1. installing attribute must return the result of running these steps or their equivalent:

    +
      +
    1. Let installingWorker be the ServiceWorker object that represents the service worker registration’s installing worker. +
    2. Return installingWorker. +
    +

    The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    +
    + +

    waiting#service-worker-registration-waiting-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.2. waiting attribute must return the result of running these steps or their equivalent:

    +
      +
    1. Let waitingWorker be the ServiceWorker object that represents the service worker registration’s waiting worker. +
    2. Return waitingWorker. +
    +

    The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    +
    + +

    active#service-worker-registration-active-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.3. active attribute must return the result of running these steps or their equivalent:

    +
      +
    1. Let activeWorker be the ServiceWorker object that represents the service worker registration’s active worker. +
    2. Return activeWorker. +
    +

    The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

    +
    +
    +

    3.2.4. scope

    +

    The scope#service-worker-registration-scope-attributeReferenced in:3.2. ServiceWorkerRegistration3.2.4. scope attribute must return service worker registration’s serialized scope url.

    +

    In the example in section 3.1.1, the value of registration.scope, obtained from navigator.serviceWorker.ready.then(function(registration) { console.log(registration.scope); }) for example, will be "https://example.com/".

    +
    +
    +

    3.2.5. update()

    +

    update()#service-worker-registration-update-methodReferenced in:3.2. ServiceWorkerRegistration3.2.5. update() method must run these steps or their equivalent:

    +
      +
    1. Let p be a promise. +
    2. Let registration be the service worker registration. +
    3. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
    4. If newestWorker is null, reject p with an "InvalidStateError" exception and abort these steps. +
    5. If the context object’s relevant settings object’s global object globalObject is a ServiceWorkerGlobalScope object, and globalObject’s associated service worker’s state is installing, reject p with an "InvalidStateError" exception and abort these steps. +
    6. Let job be the result of running Create Job with update, registration’s scope url, newestWorker’s script url, p, and the context object’s relevant settings object client. +
    7. + Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job. +
      +
    8. Return p. +
    +
    +
    + +

    The unregister() method unregisters the service worker registration. It is important to note that the currently controlled service worker client’s active worker’s containing service worker registration is effective until all the service worker clients (including itself) using this service worker registration unload. That is, the unregister() method only affects subsequent navigations.

    +

    unregister()#service-worker-registration-unregister-methodReferenced in:3.2. ServiceWorkerRegistration3.2.6. unregister() (2) (3) method must return the result of running these steps or their equivalent:

    +
      +
    1. Let p be a promise. +
    2. Let job be the result of running Create Job with unregister, the scope url of the service worker registration, null, p, and the context object’s relevant settings object client. +
    3. + Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job. +
      +
    4. Return p. +
    +
    +
    +

    3.2.7. Event handler

    +

    The following is the event handler (and its corresponding event handler event type) that must be supported, as event handler IDL attributes, by all objects implementing ServiceWorkerRegistration interface:

    + + + + + +
    event handler + event handler event type +
    onupdatefound#service-worker-registration-onupdatefound-attributeReferenced in:3.2. ServiceWorkerRegistration + updatefound +
    +
    +
    +
    + +
    partial interface Navigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +partial interface WorkerNavigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +

    The serviceWorker#navigator-service-worker-attributeReferenced in:3.3. navigator.serviceWorker (2) (3) attribute must return the ServiceWorkerContainer object that is associated with the context object.

    +
    +
    +

    3.4. ServiceWorkerContainer

    +
    [Exposed=(Window,Worker)]
    +interface ServiceWorkerContainer : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? controller;
    +  [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
    +
    +  [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
    +
    +  [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
    +  [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
    +
    +
    +  // events
    +  attribute EventHandler oncontrollerchange;
    +  attribute EventHandler onerror;
    +  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
    +};
    +
    +
    dictionary RegistrationOptions#dictdef-serviceworkercontainer-registrationoptionsReferenced in:3.4. ServiceWorkerContainer {
    +  USVString scope#dom-registrationoptions-scopeReferenced in:3.4.3. register(scriptURL, options) (2);
    +};
    +
    +

    The user agent must create a ServiceWorkerContainer object when a Navigator object or a WorkerNavigator object is created and associate it with that object.

    +

    A ServiceWorkerContainer#service-worker-container-interfaceReferenced in:3.3. navigator.serviceWorker (2) (3)3.4. ServiceWorkerContainer (2) (3) (4) (5) (6)3.4.6. Event handlers3.6. Events4.2.4. postMessage(message, transfer) (2) (3)Notify Controller Change provides capabilities to register, unregister, and update the service worker registrations, and provides access to the state of the service worker registrations and their associated service workers.

    +

    A ServiceWorkerContainer has an associated service worker client#dfn-service-worker-container-interface-clientReferenced in:3.4.1. controller3.4.2. ready3.4.3. register(scriptURL, options)3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()3.6. Events4.2.4. postMessage(message, transfer) (2) (3) (4)Notify Controller Change, which is a service worker client whose global object is associated with the Navigator object or the WorkerNavigator object that the ServiceWorkerContainer is retrieved from.

    +

    A ServiceWorkerContainer object has an associated ready promise#dfn-ready-promiseReferenced in:3.4.2. ready (2) (3) (4) (5) (a promise). It is initially set to a new promise.

    +
    + +

    controller#service-worker-container-controller-attributeReferenced in:3.4. ServiceWorkerContainer3.4.1. controller (2)3.6. Events attribute must return the result of running these steps or their equivalent:

    +
      +
    1. Let client be the context object’s service worker client. +
    2. If client is not a secure context, return undefined. +
    3. Return the ServiceWorker object that represents client’s active worker. +
    +

    navigator.serviceWorker.controller returns null if the request is a force refresh (shift+refresh). The ServiceWorker objects returned from this attribute getter that represent the same service worker are the same objects.

    +

    The behavior of the attribute getter in non-secure contexts is in discussion.

    +
    +
    + +

    ready#service-worker-container-ready-attributeReferenced in:3.4. ServiceWorkerContainer3.4.2. ready (2) attribute must return the result of running these steps or their equivalent:

    +
      +
    1. If the context object’s ready promise is settled, return the context object’s ready promise. +
    2. Let client be the context object’s service worker client. +
    3. If client is not a secure context, return the context object’s ready promise rejected with a "SecurityError" exception. +
    4. Let registration be null. +
    5. Let clientURL be client’s creation url. +
    6. + Run the following substeps in parallel: +
        +
      1. + CheckRegistration: If the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument is not null, then: +
          +
        1. Set registration to the result value. +
        +
      2. + Else: +
          +
        1. Wait until scope to registration map has a new entry. +
        2. Jump to the step labeled CheckRegistration. +
        +
      3. + If registration’s active worker is null, wait until registration’s active worker changes. +

        Implementers should consider this condition is met when the corresponding registration request gets to the step 7 of Activate algorithm.

        +
      4. Resolve context object’s ready promise with the ServiceWorkerRegistration object which represents registration. +
      +
    7. Return context object’s ready promise. +
    +

    When the ready attribute is accessed in a secure context, the returned promise will never reject. Instead, it waits until the promise resolves with a service worker registration that has an active worker.

    +
    +
    + +

    The register(scriptURL, options) method creates or updates a service worker registration for the given scope url. If successful, a service worker registration ties the provided scriptURL to a scope url, which is subsequently used for navigation matching.

    +

    register(scriptURL, options)#service-worker-container-register-methodReferenced in:3.4. ServiceWorkerContainer3.4.3. register(scriptURL, options) (2) method must run these steps or their equivalent:

    +
      +
    1. Let p be a promise. +
    2. Let client be the context object’s service worker client. +
    3. If client is not a secure context, reject p with a "SecurityError" exception and abort these steps. +
    4. Let scriptURL be the result of parsing scriptURL with entry settings object’s API base URL. +
    5. If scriptURL is failure, reject p with a TypeError and abort these steps. +
    6. If scriptURL’s scheme is not one of "http" and "https", reject p with a TypeError and abort these steps. +
    7. If any of the strings in scriptURL’s path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps. +
    8. Let scopeURL be null. +
    9. + If options.scope is not present, set scopeURL to the result of parsing a string "./" with scriptURL. +

      The scope url for the registration is set to the location of the service worker script by default.

      +
    10. Else, set scopeURL to the result of parsing options.scope with entry settings object’s API base URL. +
    11. If scopeURL is failure, reject p with a TypeError and abort these steps. +
    12. If scopeURL’s scheme is not one of "http" and "https", reject p with a TypeError and abort these steps. +
    13. If any of the strings in scopeURL’s path contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject p with a TypeError and abort these steps. +
    14. Let job be the result of running Create Job with register, scopeURL, scriptURL, p, and client. +
    15. + Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job. +
      +
    16. Return p. +
    +
    +
    + +

    getRegistration(clientURL)#service-worker-container-getregistration-methodReferenced in:3.4. ServiceWorkerContainer3.4.4. getRegistration(clientURL) method must run these steps or their equivalent:

    +
      +
    1. Let client be the context object’s service worker client. +
    2. If client is not a secure context, return a promise rejected with a "SecurityError" exception. +
    3. Let clientURL be the result of parsing clientURL with entry settings object’s API base URL. +
    4. If clientURL is failure, return a promise rejected with a TypeError. +
    5. If the origin of clientURL is not client’s origin, return a promise rejected with a "SecurityError" exception. +
    6. Let promise be a new promise. +
    7. + Run the following substeps in parallel: +
        +
      1. Let registration be the result of running Match Service Worker Registration algorithm, or its equivalent, with clientURL as its argument. +
      2. + If registration is not null, then: +
          +
        1. Resolve promise with the ServiceWorkerRegistration object which represents registration. +
        +
      3. + Else: +
          +
        1. Resolve promise with undefined. +
        +
      +
    8. Return promise. +
    +
    +
    + +

    getRegistrations()#service-worker-container-getregistrations-methodReferenced in:3.4. ServiceWorkerContainer3.4.5. getRegistrations() method must run these steps or their equivalent:

    +
      +
    1. Let client be the context object’s service worker client. +
    2. If client is not a secure context, return a promise rejected with a "SecurityError" exception. +
    3. Let promise be a new promise. +
    4. + Run the following substeps in parallel: +
        +
      1. Let array be an empty array. +
      2. + For each Record {[[key]], [[value]]} entry of scope to registration map: +
          +
        1. If the origin of the result of parsing entry.[[key]] is the same as client’s origin, add the ServiceWorkerRegistration object associated with entry.[[value]] to the array. +
        +
      3. Resolve promise with array. +
      +
    5. Return promise. +
    +
    +
    +

    3.4.6. Event handlers

    +

    The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerContainer interface:

    + + + + + + + +
    event handler + event handler event type +
    oncontrollerchange#service-worker-container-oncontrollerchange-attributeReferenced in:3.4. ServiceWorkerContainer + controllerchange +
    onerror#service-worker-container-onerror-attributeReferenced in:3.4. ServiceWorkerContainer + error +
    onmessage#service-worker-container-onmessage-attributeReferenced in:3.4. ServiceWorkerContainer + message +
    +
    +
    +
    +

    3.5. ServiceWorkerMessageEvent

    +
    [Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
    +interface ServiceWorkerMessageEvent : Event {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +
    dictionary ServiceWorkerMessageEventInit#dictdef-serviceworkermessageevent-serviceworkermessageeventinitReferenced in:3.5. ServiceWorkerMessageEvent : EventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +

    Service workers define the message event that extends the message event defined in [HTML] to allow setting a ServiceWorker object as the source of the message. For the message event, service workers use the ServiceWorkerMessageEvent#serviceworkermessage-event-interfaceReferenced in:3.5. ServiceWorkerMessageEvent (2)3.6. Events4.2.4. postMessage(message, transfer) interface.

    +
    +

    3.5.1. event.data

    +

    The data#serviceworkermessage-event-data-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.1. event.data4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    +
    +

    3.5.2. event.origin

    +

    The origin#serviceworkermessage-event-origin-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.2. event.origin4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker’s environment settings object from which the message is sent.

    +
    +
    +

    3.5.3. event.lastEventId

    +

    The lastEventId#serviceworkermessage-event-lasteventid-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.3. event.lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    +
    +

    3.5.4. event.source

    +

    The source#serviceworkermessage-event-source-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.4. event.source4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the ServiceWorker object whose associated service worker the message is sent from.

    +
    +
    +

    3.5.5. event.ports

    +

    The ports#serviceworkermessage-event-ports-attributeReferenced in:3.5. ServiceWorkerMessageEvent3.5.5. event.ports4.2.4. postMessage(message, transfer) attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

    +
    +
    +
    +

    3.6. Events

    +

    The following event is dispatched on ServiceWorker object:

    + + + + + +
    Event name + Interface + Dispatched when… +
    statechange#service-worker-statechange-eventReferenced in:3.1.4. Event handler + Event + The state attribute of the ServiceWorker object is changed. +
    +

    The following event is dispatched on ServiceWorkerRegistration object:

    + + + + + +
    Event name + Interface + Dispatched when… +
    updatefound#service-worker-registration-updatefound-eventReferenced in:3.2.7. Event handler + Event + The service worker registration’s installing worker changes. (See step 7 of the Install algorithm.) +
    +

    The following events are dispatched on ServiceWorkerContainer object:

    + + + + + + + +
    Event name + Interface + Dispatched when… +
    controllerchange#service-worker-container-controllerchange-eventReferenced in:3.4.6. Event handlers + Event + The service worker client’s active worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a service worker causes activation of the service worker registration to occur while service worker clients are using the service worker registration, navigator.serviceWorker.controller immediately reflects the active worker as the service worker that controls the service worker client.) +
    message#service-worker-container-message-eventReferenced in:3.4.6. Event handlers3.5. ServiceWorkerMessageEvent (2)4.2.4. postMessage(message, transfer) + ServiceWorkerMessageEvent + When it receives a message. +
    error#service-worker-container-error-eventReferenced in:3.4.6. Event handlers + ErrorEvent + Any error occurred from the associated service workers. +
    +
    +
    +
    +

    4. Execution Context

    +
    + Serving Cached Resources: +
    // caching.js
    +this.addEventListener("install", function(e) {
    +  e.waitUntil(
    +    // Open a cache of resources.
    +    caches.open("shell-v1").then(function(cache) {
    +      // Begins the process of fetching them.
    +      // The coast is only clear when all the resources are ready.
    +      return cache.addAll([
    +        "/app.html",
    +        "/assets/v1/base.css",
    +        "/assets/v1/app.js",
    +        "/assets/v1/logo.png",
    +        "/assets/v1/intro_video.webm"
    +      ]);
    +    })
    +  );
    +});
    +
    +this.addEventListener("fetch", function(e) {
    +  // No "fetch" events are dispatched to the service worker until it
    +  // successfully installs and activates.
    +
    +  // All operations on caches are async, including matching URLs, so we use
    +  // promises heavily. e.respondWith() even takes promises to enable this:
    +  e.respondWith(
    +    caches.match(e.request).then(function(response) {
    +      return response || fetch(e.request);
    +    }).catch(function() {
    +      return caches.match("/fallback.html");
    +    })
    +  );
    +});
    +
    +
    +

    4.1. ServiceWorkerGlobalScope

    +
    [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
    +interface ServiceWorkerGlobalScope : WorkerGlobalScope {
    +  // A container for a list of Client objects that correspond to
    +  // browsing contexts (or shared workers) that are on the origin of this SW
    +  [SameObject] readonly attribute Clients clients;
    +  [SameObject] readonly attribute ServiceWorkerRegistration registration;
    +
    +  [NewObject] Promise<void> skipWaiting();
    +
    +  attribute EventHandler oninstall;
    +  attribute EventHandler onactivate;
    +  attribute EventHandler onfetch;
    +
    +  // event
    +  attribute EventHandler onmessage; // event.source of the message events is Client object
    +
    +  // close() method inherited from WorkerGlobalScope should not be accessible.
    +};
    +
    +

    A ServiceWorkerGlobalScope#service-worker-global-scope-interfaceReferenced in:3.1.3. postMessage(message, transfer) (2)3.2.5. update()4.1. ServiceWorkerGlobalScope (2) (3) (4)4.1.4. Event handlers4.3. Clients4.4.1. event.waitUntil(f)4.7. Events6.3.2. importScripts(urls)8.3. Define Event Handler8.4. Request Functional Event DispatchRun Service Worker (2) object represents the global execution context of a service worker. A ServiceWorkerGlobalScope object has an associated service worker#dfn-service-worker-global-scope-service-workerReferenced in:3.1.3. postMessage(message, transfer)3.2.5. update()4.1.2. registration4.2.4. postMessage(message, transfer)4.2.8. navigate(url) (2)4.3.1. get(id)4.3.2. matchAll(options) (2)4.3.3. openWindow(url)4.3.4. claim() (2) (3) (4) (5)4.7. Events (2) (3)6.3.2. importScripts(urls)Run Service Worker (a service worker).

    +

    ServiceWorkerGlobalScope object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a service worker is started, kept alive and killed by their relationship to events, not service worker clients. Any type of synchronous requests must not be initiated inside of a service worker.

    +

    The close() method inherited from WorkerGlobalScope, when called on the context object, should throw an "InvalidAccessError" exception.

    +
    +

    4.1.1. clients

    +

    clients#service-worker-global-scope-clients-attributeReferenced in:4.1. ServiceWorkerGlobalScope4.1.1. clients attribute must return the Clients object that is associated with the context object.

    +
    +
    +

    4.1.2. registration

    +

    The registration#service-worker-global-scope-scope-attributeReferenced in:4.1. ServiceWorkerGlobalScope4.1.2. registration attribute must return the ServiceWorkerRegistration object that represents the service worker’s containing service worker registration.

    +
    +
    +

    4.1.3. skipWaiting()

    +

    The skipWaiting() method allows this service worker to progress from the registration’s waiting position to active even while service worker clients are using the registration.

    +

    skipWaiting()#service-worker-global-scope-skipwaiting-methodReferenced in:4.1. ServiceWorkerGlobalScope4.1.3. skipWaiting() (2) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run the following substeps in parallel: +
        +
      1. Set service worker’s skip waiting flag +
      2. + If service worker’s state is installed, then: +
          +
        1. Run Activate algorithm, or its equivalent, passing service worker’s registration as the argument. +
        +
      3. Resolve promise with undefined. +
      +
    3. Return promise. +
    +
    +
    +

    4.1.4. Event handlers

    +

    The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by all objects implementing the ServiceWorkerGlobalScope interface:

    + + + + + + + + +
    event handler + event handler event type +
    oninstall#service-worker-global-scope-oninstall-attributeReferenced in:3.1.2. state4.1. ServiceWorkerGlobalScope4.4.1. event.waitUntil(f) + install +
    onactivate#service-worker-global-scope-onactivate-attributeReferenced in:3.1.2. state4.1. ServiceWorkerGlobalScope4.4.1. event.waitUntil(f) + activate +
    onfetch#service-worker-global-scope-onfetch-attributeReferenced in:4.1. ServiceWorkerGlobalScope + fetch +
    onmessage#service-worker-global-scope-onmessage-attributeReferenced in:4.1. ServiceWorkerGlobalScope + message +
    +
    +
    +
    +

    4.2. Client

    +
    [Exposed=ServiceWorker]
    +interface Client {
    +  readonly attribute USVString url;
    +  readonly attribute FrameType frameType;
    +  readonly attribute DOMString id;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +};
    +
    +[Exposed=ServiceWorker]
    +interface WindowClient : Client {
    +  readonly attribute VisibilityState visibilityState;
    +  readonly attribute boolean focused;
    +  [NewObject] Promise<WindowClient> focus();
    +  [NewObject] Promise<WindowClient> navigate(USVString url);
    +};
    +
    +enum FrameType {
    +  "auxiliary",
    +  "top-level",
    +  "nested",
    +  "none"
    +};
    +
    +

    A Client#client-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.2. Client (2) (3)4.3. Clients4.6. ExtendableMessageEvent (2)4.6.4. event.sourceCreate Client (2) object has an associated service worker client#dfn-service-worker-client-clientReferenced in:4.2.1. url4.2.2. frameType4.2.3. id4.2.4. postMessage(message, transfer)4.2.7. focus() (2) (3)4.2.8. navigate(url) (2) (3)Create ClientCreate Window Client (a service worker client).

    +

    A WindowClient#window-client-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.2. Client (2) (3) (4)4.3. ClientsCreate Window Client (2) object has an associated visibility state#dfn-service-worker-client-visibilitystateReferenced in:4.2.5. visibilityStateCreate Window Client, which is one of visibilityState attribute value.

    +

    A WindowClient object has an associated focus state#dfn-service-worker-client-focusstateReferenced in:4.2.6. focused4.2.7. focus()Create Window Client, which is either true or false (initially false).

    +
    +

    4.2.1. url

    +

    The url#client-url-attributeReferenced in:4.2. Client4.2.1. url attribute must return the context object’s associated service worker client’s serialized creation url.

    +
    +
    +

    4.2.2. frameType

    +

    The frameType#client-frametype-attributeReferenced in:4.2. Client4.2.2. frameType attribute must return the value (in FrameType#contextframetype-enumReferenced in:4.2. Client (2) enumeration) corresponding to the first matching statement, switching on service worker client’s frame type:

    +
    +
    auxiliary +
    + "auxiliary" +

    The window client’s global object’s browsing context is an auxiliary browsing context.

    +
    top-level +
    + "top-level" +

    The window client’s global object’s browsing context is a top-level browsing context.

    +
    nested +
    + "nested" +

    The window client’s global object’s browsing context is a nested browsing context.

    +
    none +
    "none" +
    +
    +
    +

    4.2.3. id

    +

    The id#client-id-attributeReferenced in:4.2. Client4.2.3. id attribute must return its associated service worker client’s id.

    +
    +
    +

    4.2.4. postMessage(message, transfer)

    +

    The postMessage(message, transfer)#client-postmessage-methodReferenced in:4.2. Client4.2.4. postMessage(message, transfer) method must run these steps or their equivalent:

    +
      +
    1. Let newPorts be an empty array. +
    2. Let transferMap be an empty association list of Transferable objects to placeholder objects. +
    3. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. If any object is listed in transfer more than once, or any of the Transferable objects listed in transfer are marked as neutered, then throw a "DataCloneError" exception and abort these steps. +
      2. For each object x in transfer in turn, add a mapping from x to a new unique placeholder object created for x to transferMap, and if x is a MessagePort object, also append the placeholder object to newPorts. +
      +
    4. Let clonedMessage be a structured clone of message with transferMap as the transferMap. If this throws an exception, rethrow that exception and abort these steps. +
    5. Let destination be the ServiceWorkerContainer object whose service worker client is the context object’s service worker client. +
    6. If destination is null, throw an "InvalidStateError" exception. +
    7. + If the method was invoked with a second argument transfer, run these substeps: +
        +
      1. Let newOwner be the destination’s service worker client. +
      2. For each object x in transfer in turn, obtain a new object y by transferring the object x to newOwner, and replace the placeholder object that was created for the object x by the new object y wherever the placeholder exists (i.e. in clonedMessage and in newPorts). +
      +
    8. Make newPorts into a read only array. +
    9. + Queue a task that runs the following steps: +
        +
      1. Create an event e that uses the ServiceWorkerMessageEvent interface, with the event type message, which does not bubble, is not cancelable, and has no default action. +
      2. Let the data attribute of e be initialized to clonedMessage. +
      3. Let the origin attribute of e be initialized to the Unicode serialisation of the origin specified by the incumbent settings object. +
      4. Let the source attribute of e be initialized to a ServiceWorker object, which represents the service worker associated with the global object specified by the incumbent settings object. +
      5. Let the ports attribute of e be initialized to newPorts. +
      6. Dispatch e at destination. +
      +

      The task must use the DOM manipulation task source, and, for those where the event loop specified by the target ServiceWorkerContainer object’s service worker client is a browsing context event loop, must be associated with the responsible document specified by that target ServiceWorkerContainer object’s service worker client.

      +
    +
    +
    +

    4.2.5. visibilityState

    +

    The visibilityState#client-visibilitystate-attributeReferenced in:4.2. Client4.2.5. visibilityState attribute must return the context object’s visibility state.

    +
    +
    +

    4.2.6. focused

    +

    The focused#client-focused-attributeReferenced in:4.2. Client4.2.6. focused attribute must return the context object’s focus state.

    +
    +
    +

    4.2.7. focus()

    +

    The focus()#client-focus-methodReferenced in:4.2. Client4.2.7. focus() method must run these steps or their equivalent:

    +
      +
    1. If this algorithm is not allowed to show a popup, return a promise rejected with an "InvalidAccessError" exception. +
    2. Let promise be a new promise. +
    3. + Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object’s associated service worker client’s global object’s browsing context. +
      2. Let visibilityState be null. +
      3. Let focusState be null. +
      4. + Queue a task task to run the following substeps on the context object’s associated service worker client’s responsible event loop using the user interaction task source: +
          +
        1. Run the focusing steps with browsingContext. +
        2. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
        3. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
        +
      5. Wait for task to have executed. +
      6. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with the context object’s associated service worker client, visibilityState and focusState as the arguments. +
      7. If windowClient’s focus state is true, resolve promise with windowClient. +
      8. Else, reject promise with a TypeError. +
      +
    4. Return promise. +
    +
    +
    +

    4.2.8. navigate(url)

    +

    The navigate()#client-navigate-methodReferenced in:4.2. Client4.2.8. navigate(url) method must run these steps or their equivalent:

    +
      +
    1. Let url be the result of parsing url with entry settings object’s API base URL. +
    2. If url is failure, return a promise rejected with a TypeError. +
    3. If url is about:blank, return a promise rejected with a TypeError. +
    4. If the context object’s associated service worker client’s active worker is not the incumbent settings object’s global object’s service worker, return a promise rejected with a TypeError. +
    5. Let promise be a new promise. +
    6. + Run these substeps in parallel: +
        +
      1. Let browsingContext be the context object’s associated service worker client’s global object’s browsing context. +
      2. If browsingContext has discarded its Document, reject promise with a TypeError and abort these steps. +
      3. Let navigateFailed to false. +
      4. Let visibilityState be null. +
      5. Let focusState be null. +
      6. + Queue a task task to run the following substeps on the context object’s associated service worker client’s responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate browsingContext to url with replacement enabled and exceptions enabled. The source browsing context must be browsingContext. +
        2. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set navigateFailed to true. +
        3. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
        4. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
        +
      7. Wait for task to have executed (including its asynchronous steps). +
      8. If navigateFailed is true, reject promise with a TypeError and abort these steps. +
      9. + If browsingContext’s Window object’s environment settings object’s creation url’s origin is not the same as the service worker’s origin, then: +
          +
        1. Resolve promise with null. +
        2. Abort these steps. +
        +
      10. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with browsingContext’s Window object’s environment settings object, visibilityState and focusState as the arguments. +
      11. Resolve promise with windowClient. +
      +
    7. Return promise. +
    +
    +
    +
    +

    4.3. Clients

    +
    [Exposed=ServiceWorker]
    +interface Clients {
    +  // The objects returned will be new instances every time
    +  [NewObject] Promise<any> get(DOMString id);
    +  [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
    +  [NewObject] Promise<WindowClient?> openWindow(USVString url);
    +  [NewObject] Promise<void> claim();
    +};
    +
    +
    dictionary ClientQueryOptions#dictdef-clients-clientqueryoptionsReferenced in:4.3. Clients {
    +  boolean includeUncontrolled#dom-clientqueryoptions-includeuncontrolledReferenced in:4.3.2. matchAll(options) = false;
    +  ClientType type#dom-clientqueryoptions-typeReferenced in:4.3.2. matchAll(options) (2) (3) (4) = "window";
    +};
    +
    +
    enum ClientType#enumdef-clients-clienttypeReferenced in:4.3. Clients {
    +  "window",
    +  "worker",
    +  "sharedworker",
    +  "all"
    +};
    +
    +

    The user agent must create a Clients#clients-interfaceReferenced in:4.1. ServiceWorkerGlobalScope4.1.1. clients4.3. Clients (2) object when a ServiceWorkerGlobalScope object is created and associate it with that object.

    +
    +

    4.3.1. get(id)

    +

    The get(id)#clients-get-methodReferenced in:4.3. Clients4.3.1. get(id) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. + For each service worker client client whose origin is the same as the associated service worker’s origin: +
          +
        1. + If client’s id is id, then: +
            +
          1. If client is not a secure context, reject promise with a "SecurityError" exception and abort these steps. +
          2. + If client is a window client, then: +
              +
            1. Let browsingContext be client’s global object’s browsing context. +
            2. Let visibilityState be null. +
            3. Let focusState be null. +
            4. + Queue a task task to run the following substeps: +
                +
              1. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
              2. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
              +
            5. Wait for task to have executed. +
            6. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
            7. Resolve promise with windowClient and abort these steps. +
            +
          3. + Else: +
              +
            1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
            2. Resolve promise with clientObject and abort these steps. +
            +
          +
        +
      2. Resolve promise with undefined. +
      +
    3. Return promise. +
    +
    +
    +

    4.3.2. matchAll(options)

    +

    The matchAll(options)#clients-matchall-methodReferenced in:4.3. Clients4.3.2. matchAll(options) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let targetClients be an empty array. +
      2. + For each service worker client client whose origin is the same as the associated service worker’s origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop. +
        2. + If options.includeUncontrolled is false, then: +
            +
          1. If client’s active worker is the associated service worker, add client to targetClients. +
          +
        3. + Else: +
            +
          1. Add client to targetClients. +
          +
        +
      3. Let matchedClients be an empty array. +
      4. + For each service worker client client in targetClients, in the most recently focused order for window clients: +
          +
        1. + If options.type is "window", and client is a window client, then: +
            +
          1. Let browsingContext be client’s global object’s browsing context. +
          2. Let visibilityState be null. +
          3. Let focusState be null. +
          4. + Queue a task task to run the following substeps on client’s responsible event loop using the user interaction task source: +
              +
            1. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
            2. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
            +
          5. + Wait for task to have executed. +

            Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

            +
          6. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
          7. Add windowClient to matchedClients. +
          +
        2. + Else if options.type is "worker" and client is a dedicated worker client, or options.type is "sharedworker" and client is a shared worker client, then: +
            +
          1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
          2. Add clientObject to matchedClients. +
          +
        3. + Else if options.type is "all", then: +
            +
          1. + If client is a window client, then: +
              +
            1. Let browsingContext be client’s global object’s browsing context. +
            2. Let visibilityState be null. +
            3. Let focusState be null. +
            4. + Queue a task task to run the following substeps on client’s responsible event loop using the user interaction task source: +
                +
              1. Set visibilityState to browsingContext’s active document’s visibilityState attribute value. +
              2. Set focusState to the result of running the has focus steps with browsingContext’s active document as the argument. +
              +
            5. + Wait for task to have executed. +

              Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.

              +
            6. Let windowClient be the result of running Create Window Client algorithm, or its equivalent, with client, visibilityState and focusState as the arguments. +
            7. Add windowClient to matchedClients. +
            +
          2. + Else: +
              +
            1. Let clientObject be the result of running Create Client algorithm, or its equivalent, with client as the argument. +
            2. Add clientObject to matchedClients. +
            +
          +
        +
      5. Resolve promise with matchedClients. +
      +
    3. Return promise. +
    +
    +
    +

    4.3.3. openWindow(url)

    +

    The openWindow(url)#clients-openwindow-methodReferenced in:4.3. Clients4.3.3. openWindow(url) method must run these steps or their equivalent:

    +
      +
    1. Let url be the result of parsing url with entry settings object’s API base URL. +
    2. If url is failure, return a promise rejected with a TypeError. +
    3. If url is about:blank, return a promise rejected with a TypeError. +
    4. If this algorithm is not allowed to show a popup, return a promise rejected with an "<InvalidAccessError" exception. +
    5. Let promise be a new promise. +
    6. + Run these substeps in parallel: +
        +
      1. Let newContext be a new top-level browsing context. +
      2. Let openWindowFailed to false. +
      3. Let visibilityState be null. +
      4. Let focusState be null. +
      5. + Queue a task task to run the following substeps on newContext’s Window object’s environment settings object’s responsible event loop using the user interaction task source: +
          +
        1. HandleNavigate: Navigate newContext to url, with exceptions enabled and replacement enabled. +
        2. If the algorithm steps invoked in the step labeled HandleNavigate throws an exception, set openWindowFailed to true. +
        3. Set visibilityState to newContext’s active document’s visibilityState attribute value. +
        4. Set focusState to the result of running the has focus steps with newContext’s active document as the argument. +
        +
      6. Wait for task to have executed (including its asynchronous steps). +
      7. If openWindowFailed is true, reject promise with a TypeError and abort these steps. +
      8. + If newContext’s Window object’s environment settings object’s creation url’s origin is not the same as the service worker’s origin, then: +
          +
        1. Resolve promise with null. +
        2. Abort these steps. +
        +
      9. Let client be the result of running Create Window Client algorithm, or its equivalent, with newContext’s Window object’s environment settings object, visibilityState and focusState as the arguments. +
      10. Resolve promise with client. +
      +
    7. Return promise. +
    +
    +
    +

    4.3.4. claim()

    +

    The claim()#clients-claim-methodReferenced in:4.3. Clients4.3.4. claim() method must run these steps or their equivalent:

    +
      +
    1. If the service worker is not an active worker, return a promise rejected with an "InvalidStateError" exception. +
    2. Let promise be a new promise. +
    3. + Run the following substeps in parallel: +
        +
      1. + For each service worker client client whose origin is the same as the service worker’s origin: +
          +
        1. If client is not a secure context, continue to the next iteration of the loop. +
        2. Let registration be the result of running Match Service Worker Registration algorithm passing client’s creation url as the argument. +
        3. If registration is not the service worker’s containing service worker registration, continue to the next iteration of the loop. +
        4. + If client’s active worker is not the service worker, then: +
            +
          1. Invoke Handle Service Worker Client Unload with client as the argument. +
          2. Set client’s active worker to service worker. +
          3. Invoke Notify Controller Change algorithm with client as the argument. +
          +
        +
      2. Resolve promise with undefined. +
      +
    4. Return promise. +
    +
    +
    +
    +

    4.4. ExtendableEvent

    +
    [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableEvent : Event {
    +  void waitUntil(Promise<any> f);
    +};
    +
    +
    dictionary ExtendableEventInit#dictdef-extendableeventinitReferenced in:4.4. ExtendableEvent4.5. FetchEvent4.6. ExtendableMessageEvent : EventInit {
    +  // Defined for the forward compatibility across the derived events
    +};
    +
    +

    An ExtendableEvent#extendable-event-interfaceReferenced in:4.4. ExtendableEvent (2) (3) (4)4.5. FetchEvent (2)4.6. ExtendableMessageEvent (2)4.7. Events (2)8.2. Define Functional EventInstallActivate object has an associated extend lifetime promises#dfn-extend-lifetime-promisesReferenced in:4.4.1. event.waitUntil(f) (2) (3) (4)InstallActivate (an array of promises). It is initially set to null.

    +

    Service workers have two lifecycle events, install and activate. Service workers use the ExtendableEvent interface for activate event and install event.

    +

    Service worker extensions that define event handlers may also use or extend the ExtendableEvent interface.

    +
    +

    4.4.1. event.waitUntil(f)

    +

    waitUntil(f) method extends the lifetime of the event.

    +

    waitUntil(f)#extendable-event-waituntil-methodReferenced in:3.1.2. state (2)4.4. ExtendableEvent4.4.1. event.waitUntil(f) (2) (3)4.6. ExtendableMessageEvent method must run these steps or their equivalent:

    +
      +
    1. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    2. Add f to extend lifetime promises. +
    +

    In the task task in which the steps of waitUntil(f) is running, the user agent must run these steps or their equivalent:

    +
      +
    1. Let extendLifetimePromises be an empty array. +
    2. + For each event listener invoked: +
        +
      1. Let eventObject be the first argument passed to this event listener. +
      2. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
      +
    3. Do not terminate the service worker whose responsible event loop is running task until waiting for all of extendLifetimePromises settles. +
    +

    However, the user agent may impose a time limit to this lifetime extension.

    +

    Service workers and extensions that define event handlers may define their own behaviors, allowing the extend lifetime promises to suggest operation length, and the rejected state of any of the promise in extend lifetime promises to suggest operation failure.

    +

    Service workers define the following behaviors for install event and activate event:

    + +
    +
    +
    +

    4.5. FetchEvent

    +
    [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface FetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +  readonly attribute DOMString? clientId;
    +  readonly attribute boolean isReload;
    +
    +  void respondWith(Promise<Response> r);
    +};
    +
    +
    dictionary FetchEventInit#dictdef-fetchevent-fetcheventinitReferenced in:4.5. FetchEvent : ExtendableEventInit {
    +  required Request request;
    +  DOMString? clientId = null;
    +  boolean isReload = false;
    +};
    +
    +

    Service workers have an essential functional event fetch. For fetch event, service workers use the FetchEvent#fetch-event-interfaceReferenced in:4.5. FetchEvent (2) (3)4.7. EventsHandle Fetch interface which extends the ExtendableEvent interface.

    +

    Each event using FetchEvent interface has an associated potential response#fetchevent-potential-responseReferenced in:4.5.4. event.respondWith(r)Handle Fetch (a response), initially set to null, and the following associated flags that are initially unset:

    + +

    +
    +

    4.5.1. event.request

    +

    request#fetch-event-request-attributeReferenced in:4.5. FetchEvent4.5.1. event.requestHandle Fetch attribute must return the value it was initialized to.

    +
    +
    +

    4.5.2. event.clientId

    +

    clientId#fetch-event-clientid-attributeReferenced in:4.5. FetchEvent4.5.2. event.clientIdHandle Fetch attribute must return the value it was initialized to. When an event is created the attribute must be initialized to null.

    +
    +
    +

    4.5.3. event.isReload

    +

    isReload#fetch-event-isreload-attributeReferenced in:4.5. FetchEvent4.5.3. event.isReloadHandle Fetch attribute must return the value it was initialized to. When an event is created the attribute must be initialized to false.

    +

    Pressing the refresh button should be considered a reload while clicking a link and pressing the back button should not. The behavior of the Ctrl+l enter is left to the implementations of the user agents.

    +
    +
    +

    4.5.4. event.respondWith(r)

    +

    Developers can set the argument r with either a promise that resolves with a Response object or a Response object (which is automatically cast to a promise). Otherwise, a network error is returned to Fetch. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in Fetch.

    +

    respondWith(r)#fetch-event-respondwith-methodReferenced in:4.5. FetchEvent4.5.4. event.respondWith(r)6.4. Cross-Origin Resources and CORS method must run these steps or their equivalent:

    +
      +
    1. + If the dispatch flag is unset, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    2. + If the respond-with entered flag is set, then: +
        +
      1. Throw an "InvalidStateError" exception. +
      2. Abort these steps. +
      +
    3. Set the stop propagation flag and stop immediate propagation flag. +
    4. Set the respond-with entered flag. +
    5. Set the wait to respond flag. +
    6. + Run the following substeps in parallel: +
        +
      1. Wait until r settles. +
      2. + If r rejected, then: +
          +
        1. Set the respond-with error flag. +
        +
      3. + If r resolved with response, then: +
          +
        1. + If response is a Response object, then: +
            +
          1. + If response is disturbed or locked, then: +
              +
            1. Set the respond-with error flag. +
            +
          2. + Else: +
              +
            1. Let potentialResponse be a copy of response’s associated response, except for its body. +
            2. + If response’s body is non-null, run these substeps: +
                +
              1. Set potentialResponse’s body to response’s body. +
              2. Let dummyStream be an empty ReadableStream object. +
              3. Set response’s body to a new body whose stream is dummyStream. +
              4. Let reader be the result of getting a reader from dummyStream. +
              5. Read all bytes from dummyStream with reader. +
              +

              These substeps are meant to produce the observable equivalent of "piping" response’s body’s stream into potentialResponse. That is, response is left with a body with a ReadableStream object that is disturbed and locked, while the data readable from potentialResponse’s body’s stream is now equal to what used to be response’s, if response’s original body is non-null.

              +

              These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.

              +
            3. Set the potential response to potentialResponse. +
            +
          +
        2. + Else: +
            +
          1. Set the respond-with error flag. +
          +

          If the respond-with error flag is set, a network error is returned to Fetch through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value response is returned to Fetch through Handle Fetch algorithm. (See the step 22.1.)

          +
        +
      4. Unset the wait to respond flag. +
      +
    +
    +
    +
    +

    4.6. ExtendableMessageEvent

    +
    [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableMessageEvent : ExtendableEvent {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +
    dictionary ExtendableMessageEventInit#dictdef-extendablemessageevent-extendablemessageeventinitReferenced in:4.6. ExtendableMessageEvent : ExtendableEventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (Client or ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +

    Service workers define the extendable message event that extends the message event defined in [HTML] to allow extending the lifetime of the event. For the message event, service workers use the ExtendableMessageEvent#extendablemessage-event-interfaceReferenced in:3.1.3. postMessage(message, transfer)4.6. ExtendableMessageEvent (2)4.7. Events interface which extends the ExtendableEvent interface.

    +
    +

    4.6.1. event.data

    +

    The data#extendablemessage-event-data-attributeReferenced in:3.1.3. postMessage(message, transfer)4.6. ExtendableMessageEvent4.6.1. event.data attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the message being sent.

    +
    +
    +

    4.6.2. event.origin

    +

    The origin#extendablemessage-event-origin-attributeReferenced in:3.1.3. postMessage(message, transfer)4.6. ExtendableMessageEvent4.6.2. event.origin attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string. It represents the origin of the service worker client that sent the message.

    +
    +
    +

    4.6.3. event.lastEventId

    +

    The lastEventId#extendablemessage-event-lasteventid-attributeReferenced in:4.6. ExtendableMessageEvent4.6.3. event.lastEventId attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to the empty string.

    +
    +
    +

    4.6.4. event.source

    +

    The source#extendablemessage-event-source-attributeReferenced in:3.1.3. postMessage(message, transfer) (2)4.6. ExtendableMessageEvent4.6.4. event.source attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the Client object from which the message is sent.

    +
    +
    +

    4.6.5. event.ports

    +

    The ports#extendablemessage-event-ports-attributeReferenced in:3.1.3. postMessage(message, transfer)4.6. ExtendableMessageEvent4.6.5. event.ports attribute must return the value it was initialized to. When the object is created, this attribute must be initialized to null. It represents the MessagePort array being sent, if any.

    +
    +
    +
    +

    4.7. Events

    +

    The following events are dispatched on ServiceWorkerGlobalScope object:

    + + + + + + + + +
    Event name + Interface + Dispatched when… +
    install#service-worker-global-scope-install-eventReferenced in:2.1. Service Worker4.1.4. Event handlers4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f)Install + ExtendableEvent + [Lifecycle event] The service worker’s containing service worker registration’s installing worker changes. (See step 11.2 of the Install algorithm.) +
    activate#service-worker-global-scope-activate-eventReferenced in:2.1. Service Worker4.1.4. Event handlers4.4. ExtendableEvent (2)4.4.1. event.waitUntil(f)Activate + ExtendableEvent + [Lifecycle event] The service worker’s containing service worker registration’s active worker changes. (See step 15.2 of the Activate algorithm.) +
    fetch#service-worker-global-scope-fetch-eventReferenced in:2.1. Service Worker2.5. Task sources4.1.4. Event handlers4.5. FetchEvent (2)6.5. Implementer ConcernsHandle Fetch + FetchEvent + [Functional event] The http fetch invokes Handle Fetch with request. As a result of performing Handle Fetch, the service worker returns a response to the http fetch. The response, represented by a Response object, can be retrieved from a Cache object or directly from network using self.fetch(input, init) method. (A custom Response object can be another option.) +
    message#service-worker-global-scope-message-eventReferenced in:3.1.3. postMessage(message, transfer)4.1.4. Event handlers4.6. ExtendableMessageEvent (2) + ExtendableMessageEvent + When it receives a message. +
    +
    +
    +
    +

    5. Caches

    +

    To allow authors to fully manage their content caches for offline use, the Window and the WorkerGlobalScope provide the asynchronous caching methods that open and manipulate Cache objects. An origin can have multiple, named Cache objects, whose contents are entirely under the control of scripts. Caches are not shared across origins, and they are completely isolated from the browser’s HTTP cache.

    +
    +

    5.1. Constructs

    +

    A fetching record#dfn-fetching-recordReferenced in:5.1. Constructs (2) (3)5.4.2. matchAll(request, options) (2)5.4.4. addAll(requests) (2)5.4.5. put(request, response) (2)5.4.7. keys(request, options)Query CacheBatch Cache Operations (2) (3) is a Record {[[key]], [[value]]} where [[key]] is a Request and [[value]] is a Response.

    +

    A fetching record has an associated incumbent record#dfn-incumbent-recordReferenced in:5.4.2. matchAll(request, options)5.4.4. addAll(requests) (2)5.4.5. put(request, response) (2) (a fetching record). It is initially set to null.

    +

    A request to response map#dfn-request-to-response-mapReferenced in:5.4. Cache (2)5.4.2. matchAll(request, options) (2)5.4.4. addAll(requests) (2) (3) (4) (5)5.4.5. put(request, response) (2) (3) (4) (5)5.4.7. keys(request, options)6.6. PrivacyQuery CacheBatch Cache Operations (2) (3) (4) (5) (6) is a List of fetching records.

    +

    A name to cache map#dfn-name-to-cache-mapReferenced in:5.1. Constructs5.5. CacheStorage (2)5.5.1. match(request, options) (2)5.5.2. has(cacheName)5.5.3. open(cacheName) (2)5.5.4. delete(cacheName)5.5.5. keys()6.6. Privacy is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a name of the Cache object and [[value]] is a Cache object.

    +

    Each origin has an associated name to cache map.

    +
    +
    +

    5.2. Understanding Cache Lifetimes

    +

    The Cache instances are not part of the browser’s HTTP cache. The Cache objects are exactly what authors have to manage themselves. The Cache objects do not get updated unless authors explicitly request them to be. The Cache objects do not expire unless authors delete the entries. The Cache objects do not disappear just because the service worker script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the service worker that can safely operate on.

    +
    +
    +

    5.3. self.caches

    +
    partial interface Window {
    +  [SameObject] readonly attribute CacheStorage caches;
    +};
    +
    +partial interface WorkerGlobalScope {
    +  [SameObject] readonly attribute CacheStorage caches;
    +};
    +
    +
    +

    5.3.1. caches

    +

    caches#global-caches-attributeReferenced in:5.3. self.caches#window-caches-attributeReferenced in:5.3. self.caches (2)5.3.1. caches5.4. Cache attribute must return the CacheStorage object that is associated with the context object.

    +
    +
    +
    +

    5.4. Cache

    +
    [Exposed=(Window,Worker)]
    +interface Cache {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<void> add(RequestInfo request);
    +  [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
    +  [NewObject] Promise<void> put(RequestInfo request, Response response);
    +  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
    +};
    +
    +
    dictionary CacheQueryOptions#dictdef-cache-cachequeryoptionsReferenced in:5.4. Cache (2) (3) (4) (5)5.5. CacheStorageQuery Cache {
    +  boolean ignoreSearch#dom-cachequeryoptions-ignoresearchReferenced in:Query Cache = false;
    +  boolean ignoreMethod#dom-cachequeryoptions-ignoremethodReferenced in:Query Cache = false;
    +  boolean ignoreVary#dom-cachequeryoptions-ignorevaryReferenced in:Query Cache = false;
    +  DOMString cacheName#dom-cachequeryoptions-cachenameReferenced in:5.5.1. match(request, options) (2);
    +};
    +
    +
    dictionary CacheBatchOperation#dictdef-cache-cachebatchoperationReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations {
    +  DOMString type#dom-cachebatchoperation-typeReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations (2) (3) (4);
    +  Request request#dom-cachebatchoperation-requestReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)Batch Cache Operations (2) (3) (4) (5);
    +  Response response#dom-cachebatchoperation-responseReferenced in:5.4.4. addAll(requests)5.4.5. put(request, response)Batch Cache Operations (2) (3) (4) (5);
    +  CacheQueryOptions options#dom-cachebatchoperation-optionsReferenced in:5.4.6. delete(request, options)Batch Cache Operations (2) (3);
    +};
    +
    +

    A Cache#cache-interfaceReferenced in:4.7. Events5. Caches (2)5.1. Constructs (2)5.2. Understanding Cache Lifetimes (2) (3) (4) (5)5.4. Cache (2) (3) (4)5.5. CacheStorage5.5.1. match(request, options) (2)5.5.3. open(cacheName) (2)6.4. Cross-Origin Resources and CORS (2) (3) object represents a request to response map. Multiple separate objects implementing the Cache interface across document environments and worker environments can all be associated with the same request to response map simultaneously.

    +

    Cache objects are always enumerable via self.caches in insertion order (per ECMAScript 6 Map objects).

    +
    +

    5.4.1. match(request, options)

    +

    match(request, options)#cache-match-methodReferenced in:5.4. Cache5.4.1. match(request, options)5.5.1. match(request, options) (2) (3) (4) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let p be the result of running the algorithm specified in matchAll(request, options) method with request and options as the arguments. +
      2. Wait until p settles. +
      3. + If p rejects with an exception, then: +
          +
        1. Reject promise with that exception. +
        +
      4. + Else if p resolves with an array, responseArray, then: +
          +
        1. + If responseArray is an empty array, then: +
            +
          1. Resolve promise with undefined. +
          +
        2. + Else: +
            +
          1. Resolve promise with the first element of responseArray. +
          +
        +
      +
    3. Return promise. +
    +
    +
    +

    5.4.2. matchAll(request, options)

    +

    matchAll(request, options)#cache-matchall-methodReferenced in:5.4. Cache5.4.1. match(request, options)5.4.2. matchAll(request, options) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let responseArray be an empty array. +
      2. + If the optional argument request is omitted, then: +
          +
        1. + For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add a copy of entry.[[value]] to responseArray. +
          +
        2. Resolve promise with responseArray. +
        3. Abort these steps. +
        +
      3. + Else: +
          +
        1. Let r be null. +
        2. + If request is a Request object, then: +
            +
          1. Set r to request’s request. +
          2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array. +
          +
        3. + Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
          +
        4. Set r’s url’s fragment to null. +
        5. Let entries be the result of running Query Cache algorithm passing a Request object associated with r and options as the arguments. +
        6. + For each entry of entries: +
            +
          1. Let response be null. +
          2. If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, set response to a copy of incumbentRecord.[[value]]. +
          3. Else, set response to a copy of entry[1]. +
          4. + If r’s method is `HEAD` and options.ignoreMethod is false, then: +
              +
            1. Let actualResponse be response’s associated response, if response’s associated response is not a filtered response, and to response’s associated response’s internal response otherwise. +
            2. Set actualResponse’s body to null. +
            +
          5. Add response to responseArray. +
          +
        7. Resolve promise with responseArray. +
        +
      +
    3. Return promise. +
    +
    +
    +

    5.4.3. add(request)

    +

    add(request)#cache-add-methodReferenced in:5.4. Cache5.4.3. add(request) method must run these steps or their equivalent:

    +
      +
    1. Let requests be an array containing only request. +
    2. Set responseArrayPromise to the result of running the algorithm specified in addAll(requests) passing requests as the argument. +
    3. Return the result of transforming responseArrayPromise with a fulfillment handler that returns undefined. +
    +
    +
    +

    5.4.4. addAll(requests)

    +

    addAll(requests)#cache-addAll-methodReferenced in:5.4. Cache5.4.3. add(request)5.4.4. addAll(requests) method must run these steps or their equivalent:

    +
      +
    1. Let responsePromiseArray be an empty array. +
    2. Let requestArray be an empty array. +
    3. + For each request whose type is Request in requests: +
        +
      1. Let r be request’s request. +
      2. If r’s url’s scheme is not one of "http" and "https", or r’s method is not `GET`, return a promise rejected with a TypeError. +
      +
    4. + For each request in requests: +
        +
      1. Let r be the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      2. + If r’s url’s scheme is not one of "http" and "https", then: +
          +
        1. Terminate all the ongoing fetches initiated by requests with reason fatal. +
        2. Break the loop. +
        +
      3. Set r’s url’s fragment to null. +
      4. Set r’s initiator to "fetch" and destination to "subresource". +
      5. Add a Request object associated with r to requestArray. +
      6. Let responsePromise be a new promise. +
      7. + Run the following substeps in parallel: +
          +
        • Fetch r. +
        • + To process response for response, run these substeps: +
            +
          1. If response’s type is error, or response’s status is not an ok status, reject responsePromise with a TypeError. +
          2. + Else if response’s header list contains a header named `Vary`, then: +
              +
            1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
            2. Let matchAsterisk be false. +
            3. + For each f in varyHeaders: +
                +
              1. If f matches "*", set matchAsterisk to true and break the loop. +
              +
            4. If matchAsterisk is true, reject responsePromise with a TypeError. +
            5. Else, resolve responsePromise with a new Response object associated with response and a new Headers object whose guard is "immutable". +
            +
          3. Else, resolve responsePromise with a new Response object associated with response and a new Headers object whose guard is "immutable". +
          +

          This step ensures that the promise for this fetch resolves as soon as the response’s headers become available.

          +
        • To process response body for response, do nothing. +
        • To process response end-of-file for response, do nothing. +
        +
      8. Add responsePromise to responsePromiseArray. +
      +
    5. Let p be waiting for all of responsePromiseArray. +
    6. + Return the result of transforming p with a fulfillment handler that, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. Let operations be an empty array. +
      2. + For each response in responseArray with the index index: +
          +
        1. Let o be an empty object representing a CacheBatchOperation dictionary. +
        2. Set the type dictionary member of o to "put". +
        3. Set the request dictionary member of o to requestArray[index]. +
        4. Set the response dictionary member of o to response. +
        5. Add o to operations. +
        +
      3. Let resultPromise be the result of running Batch Cache Operations algorithm passing operations as the argument. +
      4. + Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
          +
        1. Let responseBodyPromiseArray be an empty array. +
        2. + For each response in responses: +
            +
          1. Let responseBodyPromise be a new promise. +
          2. + Run the following substeps in parallel: +
              +
            1. Wait for either end-of-file to have been pushed to response’s associated response r’s body or for r to have a termination reason. +
            2. + If r had a termination reason, then: +
                +
              1. + If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
                  +
                1. Set fetchingRecord in request to response map to the copy of incumbentRecord. +
                +
              2. + Else: +
                  +
                1. Delete fetchingRecord from request to response map. +
                +
              3. Reject responseBodyPromise with a TypeError. +
              +
            3. + Else: +
                +
              1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord. +
              2. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument. +
              3. + For each invalidRecord in invalidRecords: +
                  +
                1. If invalidRecord is not fetchingRecord, delete it from request to response map. +
                +
              4. Resolve responseBodyPromise with response. +
              +
            +
          3. Add responseBodyPromise to responseBodyPromiseArray. +
          +
        3. Let q be waiting for all of responseBodyPromiseArray. +
        4. Return the result of transforming q with a fulfillment handler that returns undefined. +
        +
      +
    +
    +
    +

    5.4.5. put(request, response)

    +

    put(request, response)#cache-put-methodReferenced in:5.4. Cache5.4.5. put(request, response) method must run these steps or their equivalent:

    +
      +
    1. Let r be null. +
    2. + If request is a Request object, then: +
        +
      1. Set r to request’s request. +
      2. If r’s url’s scheme is not one of "http" and "https", or r’s method is not `GET`, return a promise rejected with a TypeError. +
      +
    3. + Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      2. If r’s url’s scheme is not one of "http" and "https", return a promise rejected with a TypeError. +
      +
    4. Set r’s url’s fragment to null. +
    5. + If response’s associated response’s header list contains a header named `Vary`, then: +
        +
      1. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
      2. + For each f in varyHeaders: +
          +
        1. If f matches "*", return a promise rejected with a TypeError. +
        +
      +
    6. If response is disturbed or locked, return a promise rejected with a TypeError. +
    7. Let newResponse be a new Response object associated with response’s associated response and a new Headers object whose guard is response’s Headers' guard. +
    8. + If response’s body is non-null, run these substeps: +
        +
      1. Let dummyStream be an empty ReadableStream object. +
      2. Set response’s body to a new body whose stream is dummyStream. +
      3. Let reader be the result of getting a reader from dummyStream. +
      4. Read all bytes from dummyStream with reader. +
      +
    9. Let operations be an empty array. +
    10. Let o be an empty object representing a CacheBatchOperation dictionary. +
    11. Set the type dictionary member of o to "put". +
    12. Set the request dictionary member of o to a Request object associated with r. +
    13. Set the response dictionary member of o to newResponse. +
    14. Add o to operations. +
    15. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument. +
    16. + Return the result of transforming resultPromise with a fulfillment handler that, when called with argument responses, performs the following substeps in parallel: +
        +
      1. Wait for either end-of-file to have been pushed to responses[0]'s associated response r’s body or for r to have a termination reason. +
      2. + If r had a termination reason, then: +
          +
        1. + If the incumbent record incumbentRecord of the corresponding fetching record fetchingRecord in request to response map is not null, then: +
            +
          1. Set fetchingRecord in request to response map to the copy of incumbentRecord. +
          +
        2. + Else: +
            +
          1. Delete fetchingRecord from request to response map. +
          +
        3. Throw a TypeError. +
        +
      3. + Else: +
          +
        1. Set the incumbent record of the corresponding fetching record fetchingRecord in request to response map to the copy of fetchingRecord. +
        2. Let invalidRecords be the result of running Query Cache algorithm passing fetchingRecord.[[key]] as the argument. +
        3. + For each invalidRecord in invalidRecords: +
            +
          1. If invalidRecord is not fetchingRecord, delete it from request to response map. +
          +
        4. Return undefined. +
        +
      +
    +
    +
    +

    5.4.6. delete(request, options)

    +

    delete(request, options)#cache-delete-methodReferenced in:5.4. Cache5.4.6. delete(request, options) method must run these steps or their equivalent:

    +
      +
    1. Let r be null. +
    2. + If request is a Request object, then: +
        +
      1. Set r to request’s request. +
      2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, return a promise resolved with false. +
      +
    3. + Else if request is a string, then: +
        +
      1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
      +
    4. Set r’s url’s fragment to null. +
    5. Let operations be an empty array. +
    6. Let o be an empty object representing a CacheBatchOperation dictionary. +
    7. Set the type dictionary member of o to "delete". +
    8. Set the request dictionary member of o to a Request object associated with r. +
    9. Set the options dictionary member of o to options. +
    10. Add o to operations. +
    11. Let resultPromise be the result of running Batch Cache Operations passing operations as the argument. +
    12. + Return the result of transforming resultPromise with a fulfillment handler, when called with argument responseArray, performs the following substeps in parallel: +
        +
      1. If responseArray is not null, return true. +
      2. Else, return false. +
      +
    +
    +
    +

    5.4.7. keys(request, options)

    +

    keys(request, options)#cache-keys-methodReferenced in:5.4. Cache5.4.7. keys(request, options) method must run these steps or their equivalent:

    +
      +
    1. Let promise be a new promise. +
    2. + Run these substeps in parallel: +
        +
      1. Let resultArray be an empty array. +
      2. + If the optional argument request is omitted, then: +
          +
        1. + For each fetching record entry of its request to response map, in key insertion order: +
            +
          1. Add entry.[[key]] to resultArray. +
          +
        +
      3. + Else: +
          +
        1. Let r be null. +
        2. + If request is a Request object, then: +
            +
          1. Set r to request’s request. +
          2. If r’s method is neither `GET` nor `HEAD` and options.ignoreMethod is false, resolve promise with an empty array. +
          +
        3. + Else if request is a string, then: +
            +
          1. Set r to the associated request of the result of invoking the initial value of Request as constructor with request as its argument. If this throws an exception, return a promise rejected with that exception. +
          +
        4. Set r’s url’s fragment to null. +
        5. Let requestResponseArray be the result of running Query Cache algorithm passing a Request object that represents r and options as the arguments. +
        6. + For each requestResponse in requestResponseArray: +
            +
          1. Add requestResponse[0] to resultArray. +
          +
        +
      4. Resolve promise with resultArray. +
      +
    3. Return promise. +
    +
    +
    +
    +

    5.5. CacheStorage

    +
    [Exposed=(Window,Worker)]
    +interface CacheStorage {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<boolean> has(DOMString cacheName);
    +  [NewObject] Promise<Cache> open(DOMString cacheName);
    +  [NewObject] Promise<boolean> delete(DOMString cacheName);
    +  [NewObject] Promise<sequence<DOMString>> keys();
    +};
    +
    +

    CacheStorage interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39.

    +

    The user agent must create a CacheStorage object when a Window object or a WorkerGlobalScope object is created and associate it with that object.

    +

    A CacheStorage#cache-storage-interfaceReferenced in:5.3. self.caches (2)5.3.1. caches5.5. CacheStorage (2) (3) (4) (5) object represents a name to cache map of its associated global object’s environment settings object’s origin. Multiple separate objects implementing the CacheStorage interface across document environments and worker environments can all be associated with the same name to cache map simultaneously.

    +
    +

    5.5.1. match(request, options)

    +

    match(request, options)#cache-storage-match-methodReferenced in:5.5. CacheStorage5.5.1. match(request, options) method must run these steps or their equivalent:

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. + If options.cacheName is present, then: +
        +
      1. + Return a new promise p and run the following substeps in parallel: +
          +
        1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
            +
          1. + If options.cacheName matches entry.[[key]], then: +
              +
            1. Resolve p with the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).) +
            2. Abort these steps. +
            +
          +
        2. Reject p with a "NotFoundError" exception. +
        +
      +
    3. + Else: +
        +
      1. Let p be a promise resolved with undefined. +
      2. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. + Set p to the result of transforming itself with a fulfillment handler that, when called with argument v, performs the following substeps in parallel: +
            +
          1. If v is not undefined, return v. +
          2. Return the result of running the algorithm specified in match(request, options) method of Cache interface with request and options as the arguments (providing entry.[[value]] as thisArgument to the [[Call]] internal method of match(request, options).) +
          +
        +
      3. Return p. +
      +
    +
    +
    +

    5.5.2. has(cacheName)

    +

    has(cacheName)#cache-storage-has-methodReferenced in:5.5. CacheStorage5.5.2. has(cacheName)5.5.4. delete(cacheName) method must run these steps or their equivalent:

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. + Return a promise p resolved with the result of running the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. + If cacheName matches entry.[[key]], then: +
            +
          1. Return true. +
          +
        +
      2. Return false. +
      +
    +
    +
    +

    5.5.3. open(cacheName)

    +

    open(cacheName)#cache-storage-open-methodReferenced in:5.5. CacheStorage5.5.3. open(cacheName) method must run these steps or their equivalent:

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. Let p be a new promise. +
    3. + Run the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. + If cacheName matches entry.[[key]], then: +
            +
          1. Resolve p with a new Cache object which is a copy of entry.[[value]]. +
          2. Abort these steps. +
          +
        +
      2. Let cache be a new Cache object. +
      3. Set a newly-created Record {[[key]]: cacheName, [[value]]: cache} to name to cache map. If this cache write operation failed due to exceeding the granted quota limit, reject p with a "QuotaExceededError" exception and abort these steps. +
      4. Resolve p with cache. +
      +
    4. Return p. +
    +
    +
    +

    5.5.4. delete(cacheName)

    +

    delete(cacheName)#cache-storage-delete-methodReferenced in:5.5. CacheStorage5.5.4. delete(cacheName) method must run these steps or their equivalent:

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. Let p be the result of running the algorithm specified in has(cacheName) method with cacheName as the argument. +
    3. + Return the result of transforming p with a fulfillment handler that, when called with argument cacheExists, performs the following substeps in parallel: +
        +
      1. + If cacheExists is true, then: +
          +
        1. Delete a Record {[[key]], [[value]]} entry from its name to cache map where cacheName matches entry.[[key]]. +
        2. Return true. +
        3. Abort these steps. +
        +

        After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.

        +
      2. + Else: +
          +
        1. Return false. +
        +
      +
    +
    +
    +

    5.5.5. keys()

    +

    keys()#cache-storage-keys-methodReferenced in:5.5. CacheStorage5.5.5. keys() method must run these steps or their equivalent:

    +

    The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order.

    +
      +
    1. If the context object’s associated global object’s environment settings object is not a secure context, return a promise rejected with a "SecurityError" exception. +
    2. Let resultArray be an empty array. +
    3. + Return a promise p resolved with the result of running the following substeps: +
        +
      1. + For each Record {[[key]], [[value]]} entry of its name to cache map, in key insertion order: +
          +
        1. Add entry.[[key]] to resultArray. +
        +
      2. Return resultArray. +
      +
    +
    +
    +
    +
    +

    6. Security Considerations

    +
    +

    6.1. Secure Context

    +

    Service workers must execute in secure contexts. Service worker clients must also be secure contexts to register a service worker registration, to get access to the service worker registrations and the service workers, to do messaging with the service workers, and to be manipulated by the service workers. This effectively means that service workers and their service worker clients should be hosted over HTTPS. A user agent may allow localhost, 127.0.0.0/8, and ::1/128 for development purpose. (Note that they may still be secure contexts.) The primary reason for this restriction is to protect users from the risks associated with insecure contexts.

    +
    +
    +

    6.2. Content Security Policy

    +

    Whenever a user agent invokes Run Service Worker algorithm with a service worker serviceWorker:

    +
      +
    • If serviceWorker’s script resource was delivered with a Content-Security-Policy HTTP header containing the value policy, the user agent must enforce policy for serviceWorker. +
    • If serviceWorker’s script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value policy, the user agent must monitor policy for serviceWorker. +
    +

    +

    The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).

    +
    +
    +

    6.3. Origin Relativity

    +
    +

    6.3.1. Origin restriction

    +

    This section is non-normative.

    +

    A Service worker executes in the registering service worker client’s origin. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other origins. Therefore, service workers cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that service workers create the opportunity for a bad actor to turn a bad day into a bad eternity.

    +
    +
    +

    6.3.2. importScripts(urls)

    +

    When the importScripts(urls)#importscripts-methodReferenced in:6.3.1. Origin restriction method is called on a ServiceWorkerGlobalScope object, the user agent must import scripts into worker global scope, with the following options:

    +

    To validate the state, the user agent must do nothing.

    +

    To get a fetch result, the user agent must run the following steps:

    +
      +
    1. Let serviceWorker be the settings object’s global object’s service worker. +
    2. + If serviceWorker’s imported scripts updated flag is unset, then: +
        +
      1. Attempt to fetch each resource identified by the resulting absolute URLs, from the origin specified by settings object, using the referrer source specified by settings object, and with the blocking flag set. +
      +
    3. + Else: +
        +
      1. If there exists a corresponding Record record for url in serviceWorker’s script resource map, set the script resource to record.[[value]]. +
      2. Else, set the script resource to null. +
      +
    +

    To postprocess the fetch result, the user agent must run the following steps:

    +
      +
    1. + If serviceWorker’s imported scripts updated flag is unset, then: +
        +
      1. If the fetching attempt failed (e.g. the server returned a 4xx or 5xx status code or equivalent, or there was a DNS error), throw a "NetworkError" exception and abort all these steps. +
      2. + Else: +
          +
        1. If there exists a corresponding Record record for the resulting absolute URL url in serviceWorker’s script resource map, set record.[[value]] to the fetched script resource. +
        2. Else, set a newly-created Record {[[key]]: url, [[value]]: the fetched script resource} to serviceWorker’s script resource map. +
        +
      +
    2. Else, if the script resource is null, throw a "NetworkError" exception and abort all these steps. +
    +
    +
    +
    +

    6.4. Cross-Origin Resources and CORS

    +

    This section is non-normative.

    +

    Applications tend to cache items that come from a CDN or other origin. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to fetch many sorts of off-origin resources when appropriate CORS headers are set.

    +

    Service workers enable this by allowing Caches to fetch and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the Cache as Response objects whose corresponding responses are basic filtered response, the objects stored are Response objects whose corresponding responses are either CORS filtered responses or opaque filtered responses. They can be passed to event.respondWith(r) method in the same manner as the Response objects whose corresponding responses are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Caches to store them allows applications to avoid re-architecting in most cases.

    +
    +
    +

    6.5. Implementer Concerns

    +

    This section is non-normative.

    +

    The implementers are encouraged to note:

    +
      +
    • Plug-ins should not load via service workers. As plug-ins may get their security origins from their own urls, the embedding service worker cannot handle it. For this reason, the Handle Fetch algorithm makes the potential-navigation-or-subresource request (whose context is either <embed> or <object>) immediately fallback to the network without dispatching fetch event. +
    • Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with service workers. +
    +

    +
    +
    +

    6.6. Privacy

    +

    Service workers introduce new persistent storage features including scope to registration map (for service worker registrations and their service workers), request to response map and name to cache map (for caches), and script resource map (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages should be cleared when users intend to clear them and should maintain and interoperate with existing user controls e.g. purging all existing persistent storages.

    +
    +
    +
    +

    7. Storage Considerations

    +

    Service workers should take a dependency on Quota Management API that extends the ServiceWorkerGlobalScope with the event listeners onbeforeevicted and onevicted to detect a storage pressure and give pre-eviction information to the application.

    +

    The cache write operations in service workers when failed due to exceeding the granted quota limit should throw "QuotaExceededError" exception.

    +
    +

    8. Extensibility

    +

    Service workers are extensible from other specifications.

    +
    +

    8.1. Define API bound to Service Worker Registration

    +

    Specifications may define an API tied to a service worker registration by using partial interface definition to the ServiceWorkerRegistration interface where it may define the specification specific attributes and methods:

    +
    partial interface ServiceWorkerRegistration {
    +  // e.g. define an API namespace
    +  readonly attribute APISpaceType APISpace;
    +  // e.g. define a method
    +  Promise<T> methodName(list of arguments);
    +};
    +
    +
    +
    +

    8.2. Define Functional Event

    +

    Specifications may define a functional event by extending ExtendableEvent interface:

    +
    // e.g. define FunctionalEvent interface
    +interface FunctionalEvent : ExtendableEvent {
    +  // add a functional event’s own attributes and methods
    +};
    +
    +
    +
    +

    8.3. Define Event Handler

    +

    Specifications may define an event handler attribute for the corresponding functional event using partial interface definition to the ServiceWorkerGlobalScope interface:

    +
    partial interface ServiceWorkerGlobalScope {
    +  attribute EventHandler onfunctionalevent;
    +};
    +
    +
    +
    +

    8.4. Request Functional Event Dispatch

    +

    To request a functional event dispatch to a service worker, specifications may invoke Handle Functional Event algorithm, or its equivalent, with its service worker registration registration and the algorithm callbackSteps as the arguments.

    +

    Specifications may define an algorithm callbackSteps where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a ServiceWorkerGlobalScope object) at which it may fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm.

    +

    See an example hook defined in Notifications API.

    +
    +
    +
    +

    Appendix A: Algorithms

    +

    The following definitions are the user agent’s internal data structures used throughout the specification.

    +

    A scope to registration map#dfn-scope-to-registration-mapReferenced in:2.2.1. Lifetime2.4. Selection and Use (2)3.4.2. ready3.4.5. getRegistrations()6.6. PrivacyHandle Functional EventHandle User Agent ShutdownSet RegistrationClear RegistrationMatch Service Worker RegistrationGet Registration is a List of the Record {[[key]], [[value]]} where [[key]] is a string that represents a scope url and [[value]] is a service worker registration.

    +

    A job#dfn-jobReferenced in:Appendix A: Algorithms (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13)Create Job (2)Schedule JobFinish JobResolve Job PromiseReject Job PromiseRegisterUpdateInstallUnregister is an abstraction of one of register, update, and unregister request for a service worker registration.

    +

    A job has a job type#dfn-job-typeReferenced in:Appendix A: AlgorithmsCreate Job (2)Run Job (2) (3)Update, which is one of register, update, and unregister.

    +

    A job has a scope url#dfn-job-scope-urlReferenced in:Appendix A: Algorithms (2) (3)Create JobRegister (2) (3)UpdateUnregister (2) (a URL).

    +

    A job has a script url#dfn-job-script-urlReferenced in:Appendix A: AlgorithmsCreate JobRegister (2) (3)Update (2) (3) (4) (5) (6) (a URL).

    +

    A job has a client#dfn-job-clientReferenced in:Create JobRun JobRegister (2)UpdateUnregister (a service worker client). It is initially null.

    +

    A job has a promise#dfn-job-promiseReferenced in:Create JobSchedule Job (2)Resolve Job PromiseReject Job PromiseInstall (a promise). It is initially null.

    +

    A job has a list of equivalent job promises#dfn-job-list-of-equivalent-job-promisesReferenced in:Schedule JobResolve Job PromiseReject Job Promise (a list of promises). It is initially the empty list.

    +

    A job has a force bypass cache flag#dfn-job-force-bypass-cache-flagReferenced in:Soft Update It is initially unset.

    +

    Two jobs are equivalent#dfn-job-equivalentReferenced in:Schedule Job when their job type is the same and:

    + +

    +

    A job queue#dfn-job-queueReferenced in:Appendix A: Algorithms (2) (3) (4) (5) (6)Schedule Job (2) (3) (4)Run Job (2)Finish Job (2) (3) (4) is a queue used to synchronize the set of concurrent jobs. The job queue contains jobs as its elements. The job queue should satisfy the general properties of FIFO queue. A user agent must maintain a separate job queue for each service worker registration keyed by its scope url. A job queue is initially empty. Unless stated otherwise, the job queue referenced from the algorithm steps is a job queue for the job’s scope url.

    +
    +

    Create Job

    +
    +
    Input +
    jobType, a job type +
    scopeURL, a URL +
    scriptURL, a URL +
    promise, a promise +
    client, a service worker client +
    Output +
    job, a job +
    +
      +
    1. Let job be a new job. +
    2. Set job’s job type to jobType. +
    3. Set job’s scope url to scopeURL. +
    4. Set job’s script url to scriptURL. +
    5. Set job’s promise to promise. +
    6. Set job’s client to client. +
    7. Return job. +
    +
    +
    +

    Schedule Job

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. + If the job queue is empty, then: +
        +
      1. Push job to the job queue and invoke Run Job. +
      +
    2. + Else: +
        +
      1. Let lastJob be the element at the back of the job queue. +
      2. If job is equivalent to lastJob and lastJob’s promise has not settled, append job’s promise to lastJob’s list of equivalent job promises. +
      3. Else, push job to the job queue. +
      +
    +
    +
    +

    Run Job

    +
    +
    Input +
    none +
    Output +
    none +
    +
      +
    1. Assert: the job queue is not empty. +
    2. Let job be the element in the front of the job queue. +
    3. If job’s job type is register, invoke Register with job and continue running these steps in parallel. +
    4. + Else if job’s job type is update, invoke Update with job and continue running these steps in parallel. +

      For a register job and an update job, the user agent delays invoking Register and Update respectively until after the document initiated the job has been dispatched DOMContentLoaded event. If the job’s client is a worker client, it is delayed until after the worker script has evaluated.

      +
    5. Else if job’s job type is unregister, invoke Unregister with job and continue running these steps in parallel. +
    +
    +
    +

    Finish Job

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. Assert: the top element in the job queue is job. +
    2. Pop the top element from the job queue. +
    3. If the job queue is not empty, invoke Run Job with the top element of the job queue. +
    +
    +
    +

    Resolve Job Promise

    +
    +
    Input +
    job, a job +
    value, any +
    Output +
    none +
    +
      +
    1. Resolve job’s promise with value. +
    2. + For each promise in job’s list of equivalent job promises: +
        +
      1. Resolve promise with value. +
      +
    +
    +
    +

    Reject Job Promise

    +
    +
    Input +
    job, a job +
    reason, an exception +
    Output +
    none +
    +
      +
    1. Reject job’s promise with reason. +
    2. + For each promise in job’s list of equivalent job promises: +
        +
      1. Reject promise with reason. +
      +
    +
    +
    +

    Register

    +
    +
    Input +
    job, a job +
    Output +
    promise, a promise +
    +
      +
    1. + If the result of running Is origin potentially trustworthy with the origin of job’s script url as the argument is Not Trusted, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    2. + If the origin of job’s script url is not job’s client’s origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    3. + If the origin of job’s scope url is not job’s client’s origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    4. Let registration be the result of running the Get Registration algorithm passing job’s scope url as the argument. +
    5. + If registration is not null, then: +
        +
      1. If registration’s uninstalling flag is set, unset it. +
      2. Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument. +
      3. + If newestWorker is not null and job’s script url equals newestWorker’s script url, then: +
          +
        1. + If newestWorker is an active worker, then: +
            +
          1. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
          2. Invoke Finish Job with job and abort these steps. +
          +
        +
      +
    6. + Else: +
        +
      1. Invoke Set Registration algorithm passing job’s scope url as its argument. +
      +
    7. Invoke Update algorithm, or its equivalent, passing job as the argument. +
    +
    +
    +

    Update

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. Let registration be the result of running the Get Registration algorithm passing job’s scope url as the argument. +
    2. + If registration is null or registration’s uninstalling flag is set, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    3. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument. +
    4. + If job’s job type is update, and newestWorker’s script url is not job’s script url, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    5. + Let r be the associated request of the result of invoking the initial value of Request as constructor with job’s serialized script url. If this throws an exception, then: +
        +
      1. Invoke Reject Job Promise with job and the exception. +
      2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      3. Invoke Finish Job with job and abort these steps. +
      +
    6. Set r’s initiator to "" and destination to "serviceworker". +
    7. Set r’s client to job’s client. +
    8. + Append `Service-Worker`/`script` to r’s header list. +

      See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.

      +
    9. Set r’s skip service worker flag, r’s synchronous flag, and r’s redirect mode to "error". +
    10. + If newestWorker is not null and registration’s last update check time is not null, then: +
        +
      1. If the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, or force bypass cache flag is set, set r’s cache mode to "reload". +
      +

      Even if the cache mode is not set to "reload", the user agent obeys Cache-Control header’s max-age value in the network layer to determine if it should bypass the browser cache.

      +
    11. Let response be the result of running fetch using r. +
    12. + If response is a network error or response’s status is not in the range 200 to 299, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError. +
      2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      3. Invoke Finish Job with job and abort these steps. +
      +
    13. + Extract a MIME type from the response’s header list. If this MIME type (ignoring parameters) is not one of text/javascript, application/x-javascript, and application/javascript, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      3. Invoke Finish Job with job and abort these steps. +
      +
    14. + Let serviceWorkerAllowed be the result of parsing `Service-Worker-Allowed` in response’s header list. +

      See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.

      +
    15. + If serviceWorkerAllowed is failure, then: +
        +
      1. Invoke Reject Job Promise with job and a TypeError. +
      2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      3. Invoke Finish Job with job and abort these steps. +
      +
    16. Let scopeURL be registration’s scope url. +
    17. Let maxScopeString be null. +
    18. + If serviceWorkerAllowed is null, then: +
        +
      1. Set maxScopeString to "/" concatenated with the strings, except the last string that denotes the script’s file name, in job’s script url’s path (including empty strings), separated from each other by "/". +
      +
    19. + Else: +
        +
      1. Let maxScope be the result of parsing serviceWorkerAllowed with job’s script url. +
      2. Set maxScopeString to "/" concatenated with the strings in maxScope’s path (including empty strings), separated from each other by "/". +
      +
    20. Let scopeString be "/" concatenated with the strings in scopeURL’s path (including empty strings), separated from each other by "/". +
    21. If scopeString starts with maxScopeString, do nothing. +
    22. + Else: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      3. Invoke Finish Job with job and abort these steps. +
      +
    23. If response’s cache state is not "local", set registration’s last update check time to the current time. +
    24. + If newestWorker is not null, newestWorker’s script url equals job’s script url with the exclude fragments flag set, and response is a byte-for-byte match with the script resource of newestWorker, then: +
        +
      1. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    25. + Else: +
        +
      1. Let worker be a new service worker. +
      2. Generate a unique opaque string and set worker’s id to the value. +
      3. Set worker’s script url to job’s script url, worker’s script resource to the script resource retrieved from the fetched response. +
      4. Invoke Run Service Worker algorithm with worker as the argument. +
      5. + If an uncaught runtime script error occurs during the above step, then: +
          +
        1. Invoke Reject Job Promise with job and a TypeError. +
        2. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
        3. Invoke Finish Job with job and abort these steps. +
        +
      +
    26. Invoke Install algorithm, or its equivalent, with job, worker, and registration as its arguments. +
    +
    +
    +

    Soft Update

    +

    The user agent may call this as often as it likes to check for updates.

    +
    +
    Input +
    registration, a service worker registration +
    force bypass cache flag, an optional flag unset by default +

    Implementers may use the force bypass cache flag to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs.

    +
    Output +
    None +
    +
      +
    1. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
    2. If newestWorker is null, abort these steps. +
    3. Let job be the result of running Create Job with update, registration’s scope url, newestWorker’s script url, a new promise, and null. +
    4. Set job’s force bypass cache flag if its force bypass cache flag is set. +
    5. + Run the following substep in parallel: +
        +
      1. Invoke Schedule Job with job. +
      +
    +
    +
    +

    Install

    +
    +
    Input +
    job, a job +
    worker, a service worker +
    registration, a service worker registration +
    Output +
    none +
    +
      +
    1. Let installFailed be false. +
    2. Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument. +
    3. Set registration’s installing worker to worker. +
    4. Run the Update State algorithm passing registration’s installing worker and installing as the arguments. +
    5. Assert: job’s promise is not null. +
    6. Invoke Resolve Job Promise with job and the ServiceWorkerRegistration object which represents registration. +
    7. Queue a task to fire a simple event named updatefound at all the ServiceWorkerRegistration objects for all the service worker clients whose creation url matches registration’s scope url and all the service workers whose containing service worker registration is registration. +
    8. Let installingWorker be registration’s installing worker. +
    9. Invoke Run Service Worker algorithm with installingWorker as the argument. +
    10. + Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the ExtendableEvent interface, with the event type install, which does not bubble, is not cancelable, and has no default action. +
      2. Dispatch e at installingWorker’s environment settings object’s global object globalObject. +
      3. Let extendLifetimePromises be an empty array. +
      4. + For each event listener invoked: +
          +
        1. + If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling. +
          2. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
          3. Set registration’s installing worker to null. +
          4. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
          5. Invoke Finish Job with job and abort these steps. +
          +
        2. Let eventObject be the first argument passed to this event listener. +
        3. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
        +
      5. Let p be waiting for all of extendLifetimePromises. +
      6. + Run the following substeps in parallel: +
          +
        1. Wait until p settles. +
        2. If p rejected, set installFailed to true. +
        3. Else if p resolved with a value, do nothing. +
        +
      +

      If task is discarded or the script has been aborted by the termination of installingWorker, set installFailed to true.

      +
    11. Wait for task to have executed or been discarded. +
    12. + If installFailed is true, then: +
        +
      1. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
      2. Set registration’s installing worker to null. +
      3. If newestWorker is null, invoke Clear Registration algorithm passing registration as its argument. +
      4. Invoke Finish Job with job and abort these steps. +
      +
    13. Set registration’s installing worker’s imported scripts updated flag. +
    14. + If registration’s waiting worker is not null, then: +
        +
      1. Terminate registration’s waiting worker. +
      2. Run the Update State algorithm passing registration’s waiting worker and redundant as the arguments. +
      3. The user agent may abort in-flight requests triggered by registration’s waiting worker. +
      +
    15. Set registration’s waiting worker to registration’s installing worker. +
    16. Set registration’s installing worker to null. +
    17. Run the Update State algorithm passing registration’s waiting worker and installed as the arguments. +
    18. + If registration’s waiting worker’s skip waiting flag is set, then: +
        +
      1. Run Activate algorithm, or its equivalent, passing registration as the argument. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    19. Invoke Finish Job with job. +
    20. Wait for all the tasks queued by Update State invoked in this algorithm have executed. +
    21. Wait until no service worker client is using registration or registration’s waiting worker’s skip waiting flag is set. +
    22. If registration’s waiting worker waitingWorker is not null and waitingWorker’s skip waiting flag is not set, invoke Activate algorithm, or its equivalent, with registration as its argument. +
    +
    +
    +

    Activate

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    None +
    +
      +
    1. Let activatingWorker be registration’s waiting worker. +
    2. Let exitingWorker be registration’s active worker. +
    3. If activatingWorker is null, abort these steps. +
    4. + If exitingWorker is not null, then: +
        +
      1. Wait for exitingWorker to finish handling any in-progress requests. +
      2. Terminate exitingWorker. +
      3. Run the Update State algorithm passing exitingWorker and redundant as the arguments. +
      +
    5. Set registration’s active worker to activatingWorker. +
    6. Set registration’s waiting worker to null. +
    7. + Run the Update State algorithm passing registration’s active worker and activating as the arguments. +

      Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated.

      +
    8. + For each service worker client client whose creation url matches registration’s scope url: +
        +
      1. If client is a window client, unassociate client’s responsible document from its application cache, if it has one. +
      2. Else if client is a shared worker client, unassociate client’s global object from its application cache, if it has one. +
      +

      Resources will now use the service worker registration instead of the existing application cache.

      +
    9. + For each service worker client client who is using registration: +
        +
      1. Set client’s active worker to registration’s active worker. +
      2. Invoke Notify Controller Change algorithm with client as the argument. +
      +
    10. Let activeWorker be registration’s active worker. +
    11. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    12. + Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the ExtendableEvent interface, with the event type activate, which does not bubble, is not cancelable, and has no default action. +
      2. Dispatch e at activeWorker’s environment settings object’s global object. +
      3. Let extendLifetimePromises be an empty array. +
      4. + For each event listener invoked: +
          +
        1. If any uncaught runtime script error occurs, report the error for the script per the runtime script errors handling. +
        2. Let eventObject be the first argument passed to this event listener. +
        3. Append eventObject’s extend lifetime promises to extendLifetimePromises. +
        +
      5. Let p be waiting for all of extendLifetimePromises. +
      +
    13. Wait for task to have executed and p defined in task has settled, or task to have been discarded or the script to have been aborted by the termination of activeWorker. +
    14. Run the Update State algorithm passing registration’s active worker and activated as the arguments. +
    +
    +
    +

    Run Service Worker

    +
    +
    Input +
    serviceWorker, a service worker +
    Output +
    None +
    +
      +
    1. Assert: serviceWorker has the script resource successfully fetched against its script url. +
    2. If serviceWorker is already running, abort these steps. +
    3. Let workerGlobalScope be a new ServiceWorkerGlobalScope object. +
    4. Let workerEventLoop be a newly created event loop. +
    5. If serviceWorker is an active worker, and there are any tasks queued in serviceWorker’s containing service worker registration’s task queues, queue them to serviceWorker’s event loop’s task queues in the same order using their original task sources. +
    6. + Let settingsObject be a new environment settings object whose algorithms are defined as follows: +
      +
      The script execution environments +
      When the environment settings object is created, for each language supported by the user agent, create an appropriate execution environment as defined by the relevant specification. +
      When a script execution environment is needed, return the appropriate one from those created when the environment settings object was created. +
      The global object +
      Return workerGlobalScope. +
      The responsible event loop +
      Return workerEventLoop. +
      The referrer source +
      Return serviceWorker’s script url. +
      The API URL character encoding +
      Return UTF-8. +
      The API base URL +
      Return serviceWorker’s script url. +
      The origin and effective script origin +
      Return its registering service worker client’s origin. +
      +
    7. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context. +
    8. Let source be the result of running the UTF-8 decode algorithm on serviceWorker’s script resource scriptResource. +
    9. Let language be JavaScript. +
    10. In the newly created execution environment, create a JavaScript global environment whose global object is workerGlobalScope. (The JavaScript global environment whose global object is a ServiceWorkerGlobalScope object is defined as the service worker environment, which is a type of worker environments.) +
    11. Let script be a new script. +
    12. Obtain the appropriate script execution environment for the scripting language language from settingsObject. +
    13. Parse/compile/initialize source using that script execution environment, as appropriate for language, and thus obtain a code entry-point. If the script was not compiled successfully, let the code entry-point be a no-op script, and act as if a corresponding uncaught script error had occurred. +
    14. Let script’s settings object be settingsObject. +
    15. Jump to the script’s code entry-point, and let that run until it either returns, fails to catch an exception, or gets aborted by the kill a worker or Terminate Service Worker algorithms. +
    16. + If scriptResource’s has ever been evaluated flag is unset, then: +
        +
      1. + Set workerGlobalScope’s associated service worker’s set of event types to handle to the set of event types created from settingsObject’s global object’s associated list of event listeners' event types. +

        If the global object’s associated list of event listeners does not have any event listener added at this moment, the service worker’s set of event types to handle is set to an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script.

        +
      2. Set scriptResource’s has ever been evaluated flag. +
      +
    17. Run the responsible event loop specified by settingsObject until it is destroyed. +
    18. Empty workerGlobalScope’s list of active timers. +
    +
    +
    +

    Terminate Service Worker

    +
    +
    Input +
    serviceWorker, a service worker +
    Output +
    None +
    +
      +
    1. If serviceWorker is not running, abort these steps. +
    2. Let serviceWorkerGlobalScope be serviceWorker environment settings object’s global object. +
    3. Set serviceWorkerGlobalScope’s closing flag to true. +
    4. + If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in serviceWorkerGlobalScope’s event loop’s task queues, queue them to serviceWorker’s containing service worker registration’s corresponding task queues in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from serviceWorkerGlobalScope’s event loop’s task queues without processing them. +

      This effectively means that the fetch events and the other functional events such as push events are backed up by the registration’s task queues while the other tasks including message events are discarded.

      +
    5. Abort the script currently running in serviceWorker. +
    +
    +
    +

    Handle Fetch

    +

    The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.

    +
    +
    Input +
    request, a request +
    Output +
    response, a response +
    +
      +
    1. Let handleFetchFailed be false. +
    2. Let respondWithEntered be false. +
    3. Let eventCanceled be false. +
    4. Let r be a new Request object associated with request. +
    5. Let headersObject be r’s headers attribute value. +
    6. Set headersObject’s guard to immutable. +
    7. Let response be null. +
    8. Let registration be null. +
    9. Let client be the service worker client that corresponds to request’s client. +
    10. Assert: request’s destination is not "serviceworker". +
    11. + If request is a potential-navigation-or-subresource request, then: +
        +
      1. Return null. +
      +
    12. + Else if request is a non-subresource request, then: +

      If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration.

      +
        +
      1. If client is not a secure context, return null. +
      2. If request is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null. +
      3. Set registration to the result of running Match Service Worker Registration algorithm, or its equivalent, passing request’s url as the argument. +
      4. If registration is null or registration’s active worker is null, return null. +
      5. Set client’s active worker to registration’s active worker. +
      +

      From this point, the service worker client starts to use its active worker’s containing service worker registration.

      +
    13. + Else if request is a subresource request, then: +
        +
      1. If client’s active worker is non-null, set registration to client’s active worker’s containing service worker registration. +
      2. Else, return null. +
      +
    14. Let activeWorker be registration’s active worker. +
    15. + If activeWorker’s set of event types to handle does not contain fetch, return null. +

      To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker’s global during the very first script execution.

      +
    16. If activeWorker’s state is activating, wait for activeWorker’s state to become activated. +
    17. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    18. + Queue a task task to run the following substeps: +
        +
      1. Create a trusted event e that uses the FetchEvent interface, with the event type fetch, which does not bubble and has no default action. +
      2. Let the request attribute of e be initialized to r. +
      3. Let the clientId attribute of e be initialized to client’s id if request is not a non-subresource request, and to null otherwise. +
      4. Let the isReload attribute of e be initialized to true if request’s client is a window client and the event was dispatched with the user’s intention for the page reload, and false otherwise. +
      5. Dispatch e at activeWorker’s environment settings object’s global object. +
      6. + For each event listener invoked: +
          +
        1. + If any uncaught runtime script error occurs, then: +
            +
          1. Report the error for the script per the runtime script errors handling. +
          2. Abort these steps. +
          +
        2. Let event be the event for which this event listener was invoked. +
        3. If event’s respond-with entered flag is set, set respondWithEntered to true. +
        4. + If event’s wait to respond flag is set, then: +
            +
          1. Wait until event’s wait to respond flag is unset. +
          2. If event’s respond-with error flag is set, set handleFetchFailed to true. +
          3. Else, set response to event’s potential response. +
          +
        5. If event’s canceled flag is set, set eventCanceled to true. +
        +
      +

      If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.

      +

      The task must use activeWorker’s event loop and the handle fetch task source.

      +
    19. Wait for task to have executed or been discarded. +
    20. + If respondWithEntered is false, then: +
        +
      1. If eventCanceled is true, return a network error and continue running these substeps in parallel. +
      2. Else, return null and continue running these substeps in parallel. +
      3. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
      4. Abort these steps. +
      +
    21. + If handleFetchFailed is true, then: +
        +
      1. Return a network error and continue running these substeps in parallel. +
      2. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
      +
    22. + Else: +
        +
      1. Return response and continue running these substeps in parallel. +
      2. If request is a non-subresource request, or request is a subresource request and the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
      +
    +
    +
    +

    Handle Functional Event

    +
    +
    Input +
    registration, a service worker registration +
    callbackSteps, an algorithm +
    Output +
    None +
    +
      +
    1. Assert: a Record with the [[value]] equals to registration is contained in scope to registration map. +
    2. Assert: registration’s active worker is not null. +
    3. Let activeWorker be registration’s active worker. +
    4. + If activeWorker’s set of event types to handle does not contain the event type for this functional event, return. +

      To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker’s global during the very first script execution.

      +
    5. If activeWorker’s state is activating, wait for activeWorker’s state to become activated. +
    6. Invoke Run Service Worker algorithm with activeWorker as the argument. +
    7. + Queue a task task to invoke callbackSteps with activeWorker’s environment settings object’s global object as its argument. +

      The task must use activeWorker’s event loop and the handle functional event task source.

      +
    8. Wait for task to have executed or been discarded. +
    9. If the time difference in seconds calculated by the current time minus registration’s last update check time is greater than 86400, invoke Soft Update algorithm, or its equivalent, with registration. +
    +
    +
    +

    Handle Service Worker Client Unload

    +

    The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.

    +
    +
    Input +
    client, a service worker client +
    Output +
    None +
    +
      +
    1. Run the following steps atomically. +
    2. Let registration be the service worker registration used by client. +
    3. If registration is null, abort these steps. +
    4. If any other service worker client is using registration, abort these steps. +
    5. If registration’s uninstalling flag is set, invoke Clear Registration algorithm passing registration as its argument and abort these steps. +
    6. If registration’s waiting worker is not null, run Activate algorithm, or its equivalent, with registration as the argument. +
    +
    +
    +

    Handle User Agent Shutdown

    +
    +
    Input +
    None +
    Output +
    None +
    +
      +
    1. + For each Record {[[key]], [[value]]} entry of its scope to registration map: +
        +
      1. Let registration be entry.[[value]]. +
      2. + If registration’s installing worker installingWorker is not null, then: +
          +
        1. If the result of running Get Newest Worker with registration is installingWorker, invoke Clear Registration with registration and continue to the next iteration of the loop. +
        2. Else, set registration’s installing worker to null. +
        +
      3. + If registration’s waiting worker is not null, run the following substep in parallel: +
          +
        1. Invoke Activate with registration. +
        +
      +
    +
    +
    +

    Unregister

    +
    +
    Input +
    job, a job +
    Output +
    none +
    +
      +
    1. + If the origin of job’s scope url is not job’s client’s origin, then: +
        +
      1. Invoke Reject Job Promise with job and a "SecurityError" exception. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    2. Let registration be the result of running Get Registration algorithm passing job’s scope url as the argument. +
    3. + If registration is null, then: +
        +
      1. Invoke Resolve Job Promise with job and false. +
      2. Invoke Finish Job with job and abort these steps. +
      +
    4. Set registration’s uninstalling flag. +
    5. Invoke Resolve Job Promise with job and true. +
    6. + If no service worker client is using registration, then: +
        +
      1. If registration’s uninstalling flag is unset, invoke Finish Job with job and abort these steps. +
      2. Invoke Clear Registration algorithm passing registration as its argument. +
      +

      When the registration is being used for a client, the deletion of the registration is handled by the Handle Service Worker Client Unload algorithm.

      +
    7. Invoke Finish Job with job. +
    +
    +
    +

    Set Registration

    +
    +
    Input +
    scope, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let scopeString be serialized scope with the exclude fragment flag set. +
    3. Let registration be a new service worker registration whose scope url is set to scope. +
    4. Set a newly-created Record {[[key]]: scopeString, [[value]]: registration} to scope to registration map. +
    5. Return registration. +
    +
    +
    +

    Clear Registration

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    None +
    +
      +
    1. Run the following steps atomically. +
    2. + If registration’s installing worker is not null, then: +
        +
      1. Terminate registration’s installing worker. +
      2. Run the Update State algorithm passing registration’s installing worker and redundant as the arguments. +
      3. Set registration’s installing worker to null. +
      4. The user agent may abort in-flight requests triggered by registration’s installing worker. +
      +
    3. + If registration’s waiting worker is not null, then: +
        +
      1. Terminate registration’s waiting worker. +
      2. Run the Update State algorithm passing registration’s waiting worker and redundant as the arguments. +
      3. Set registration’s waiting worker to null. +
      4. The user agent may abort in-flight requests triggered by registration’s waiting worker. +
      +
    4. + If registration’s active worker is not null, then: +
        +
      1. Terminate registration’s active worker. +
      2. Run the Update State algorithm passing registration’s active worker and redundant as the arguments. +
      3. Set registration’s active worker to null. +
      4. The user agent may abort in-flight requests triggered by registration’s active worker. +
      +
    5. Delete a Record {[[key]], [[value]]} entry from scope to registration map where registration’s scope url is the result of parsing entry.[[key]]. +
    +
    +
    +

    Update State

    +
    +
    Input +
    worker, a service worker +
    state, a service worker’s state +
    Output +
    None +
    +
      +
    1. Set worker’s state to state. +
    2. Let serviceWorkers be an array containing all the ServiceWorker objects associated with worker. +
    3. + For each serviceWorker in serviceWorkers: +
        +
      1. Queue a task to fire a simple event named statechange at serviceWorker. +
      +

      The task must use serviceWorker’s relevant settings object’s responsible event loop and the DOM manipulation task source.

      +
    +
    +
    +

    Notify Controller Change

    +
    +
    Input +
    client, a service worker client +
    Output +
    None +
    +
      +
    1. Assert: client is not null. +
    2. Queue a task to fire a simple event named controllerchange at the ServiceWorkerContainer object client is associated with. +
    +

    The task must use client’s responsible event loop and the DOM manipulation task source.

    +
    +
    +

    Match Service Worker Registration

    +
    +
    Input +
    clientURL, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let clientURLString be serialized clientURL. +
    3. Let matchingScope be the empty string. +
    4. + Set matchingScope to the longest [[key]] in scope to registration map which the value of clientURLString starts with, if it exists. +

      The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix").

      +
    5. Let parsedMatchingScope be null. +
    6. If matchingScope is not the empty string, set parsedMatchingScope to the result of parsing matchingScope. +
    7. Let registration be the result of running Get Registration algorithm passing parsedMatchingScope as the argument. +
    8. If registration is not null and registration’s uninstalling flag is set, return null. +
    9. Return registration. +
    +
    +
    +

    Get Registration

    +
    +
    Input +
    scope, a URL +
    Output +
    registration, a service worker registration +
    +
      +
    1. Run the following steps atomically. +
    2. Let scopeString be the empty string. +
    3. If scope is not null, set scopeString to serialized scope with the exclude fragment flag set. +
    4. Let registration be null. +
    5. + For each Record {[[key]], [[value]]} entry of its scope to registration map: +
        +
      1. If scopeString matches entry.[[key]], set registration to entry.[[value]]. +
      +
    6. Return registration. +
    +
    +
    +

    Get Newest Worker

    +
    +
    Input +
    registration, a service worker registration +
    Output +
    worker, a service worker +
    +
      +
    1. Run the following steps atomically. +
    2. Let newestWorker be null. +
    3. If registration’s installing worker is not null, set newestWorker to registration’s installing worker. +
    4. Else if registration’s waiting worker is not null, set newestWorker to registration’s waiting worker. +
    5. Else if registration’s active worker is not null, set newestWorker to registration’s active worker. +
    6. Return newestWorker. +
    +
    +
    +

    Create Client

    +
    +
    Input +
    client, a service worker client +
    Output +
    clientObject, a Client object +
    +
      +
    1. Let clientObject be a new Client object. +
    2. Set clientObject’s service worker client to client. +
    3. Return clientObject. +
    +
    +
    +

    Create Window Client

    +
    +
    Input +
    client, a service worker client +
    visibilityState, a string +
    focusState, a boolean +
    Output +
    windowClient, a WindowClient object +
    +
      +
    1. Let windowClient be a new WindowClient object. +
    2. Set windowClient’s service worker client to client. +
    3. Set windowClient’s visibility state to visibilityState. +
    4. Set windowClient’s focus state to focusState. +
    5. Return windowClient. +
    +
    +
    +

    Query Cache

    +
    +
    Input +
    request, a Request object +
    options, a CacheQueryOptions object, optional +
    targetStorage, an array that has [Request, Response] pairs as its elements, optional +
    Output +
    resultArray, an array that has [Request, Response] pairs as its elements +
    +
      +
    1. Let requestArray be an empty array. +
    2. Let responseArray be an empty array. +
    3. Let resultArray be an empty array. +
    4. If options.ignoreMethod is false and request.method is neither "GET" nor "HEAD", return resultArray. +
    5. Let cachedURL and requestURL be null. +
    6. Let serializedCachedURL and serializedRequestURL be null. +
    7. + If the optional argument targetStorage is omitted, then: +
        +
      1. + For each fetching record entry of its request to response map, in key insertion order: +
          +
        1. Set cachedURL to entry.[[key]]'s associated request’s url. +
        2. Set requestURL to request’s associated request’s url. +
        3. + If options.ignoreSearch is true, then: +
            +
          1. Set cachedURL’s query to the empty string. +
          2. Set requestURL’s query to the empty string. +
          +
        4. Set serializedCachedURL to serialized cachedURL. +
        5. Set serializedRequestURL to serialized requestURL. +
        6. + If serializedCachedURL matches serializedRequestURL, then: +
            +
          1. Add a copy of entry.[[key]] to requestArray. +
          2. Add a copy of entry.[[value]] to responseArray. +
          +
        +
      +
    8. + Else: +
        +
      1. + For each record in targetStorage: +
          +
        1. Set cachedURL to record[0]'s associated request’s url. +
        2. Set requestURL to request’s associated request’s url. +
        3. + If options.ignoreSearch is true, then: +
            +
          1. Set cachedURL’s query to the empty string. +
          2. Set requestURL’s query to the empty string. +
          +
        4. Set serializedCachedURL to serialized cachedURL. +
        5. Set serializedRequestURL to serialized requestURL. +
        6. + If serializedCachedURL matches serializedRequestURL, then: +
            +
          1. Add record[0] to requestArray. +
          2. Add record[1] to responseArray. +
          +
        +
      +
    9. + For each cachedResponse in responseArray with the index index: +
        +
      1. Let cachedRequest be the indexth element in requestArray. +
      2. + If cachedResponse’s response’s header list contains no header named `Vary`, or options.ignoreVary is true, then: +
          +
        1. Add an array [cachedRequest, cachedResponse] to resultArray. +
        2. Continue to the next iteration of the loop. +
        +
      3. Let varyHeaders be the array containing the elements corresponding to the field-values of the Vary header. +
      4. Let matchFailed be false. +
      5. + For each f in varyHeaders: +
          +
        1. + If f matches "*", or the result of running cachedRequest.headers object’s get(name) method with f as the argument does not match the result of running request.headers object’s get(name) method with f as the argument, then: +
            +
          1. Set matchFailed to true. +
          2. Break the loop. +
          +
        +
      6. If matchFailed is false, add an array [cachedRequest, cachedResponse] to resultArray. +
      +
    10. Return resultArray. +
    +
    +
    +

    Batch Cache Operations

    +
    +
    Input +
    operations, an array of CacheBatchOperation dictionary objects +
    Output +
    promise, a promise resolves with an array of Response objects. +
    +
      +
    1. Let p be a promise resolved with no value. +
    2. + Return the result of transforming p with a fulfillment handler that performs the following substeps in parallel: +
        +
      1. Let itemsCopy be a new request to response map that is a copy of its context object’s request to response map. +
      2. Let addedRecords be an empty array. +
      3. + Try running the following substeps atomically: +
          +
        1. Let resultArray be an empty array. +
        2. + For each operation in operations with the index index: +
            +
          1. If operation.type matches neither "delete" nor "put", throw a TypeError. +
          2. If operation.type matches "delete" and operation.response is not null, throw a TypeError. +
          3. If the result of running Query Cache algorithm passing operation.request, operation.options, and addedRecords as the arguments is not an empty array, throw an "InvalidStateError" exception. +
          4. Let requestResponseArray be the result of running Query Cache algorithm passing operation.request and operation.options as the arguments. +
          5. + For each requestResponse in requestResponseArray: +
              +
            1. If operation.type matches "delete", remove the corresponding fetching record from request to response map. +
            +
          6. + If operation.type matches "put", then: +
              +
            1. If operation.response is null, throw a TypeError. +
            2. Let r be operation.request's associated request. +
            3. If r’s url’s scheme is not one of "http" and "https", throw a TypeError. +
            4. If r’s method is not `GET`, throw a TypeError. +
            5. If operation.options is not null, throw a TypeError. +
            6. If there exists a corresponding fetching record fetchingRecord for operation.request and operation.response in request to response map, set fetchingRecord.[[value]] to operation.response. +
            7. + Else, set a newly-created fetching record {[[key]]: operation.request, [[value]]: operation.response} to request to response map. +

              The cache commit is allowed as long as the response’s headers are available.

              +
            8. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "QuotaExceededError" exception. +
            9. Add an array [operation.request, operation.response] to addedRecords. +
            +
          7. Add operation.response to resultArray. +
          +
        3. Return resultArray. +
        +
      4. + And then, if an exception was thrown, then: +
          +
        1. Set the context object’s request to response map to itemsCopy. +
        2. Throw the exception +
        +
      +
    +
    +
    +
    +

    Appendix B: Extended HTTP headers

    +
    +

    Service Worker Script Request

    +

    An HTTP request to fetch a service worker’s script resource will include the following header:

    +
    +
    `Service-Worker` +
    + Indicates this request is a service worker’s script resource request. +

    This header helps administrators log the requests and detect threats.

    +
    +
    +
    +

    Service Worker Script Response

    +

    An HTTP response to a service worker’s script resource request can include the following header:

    +
    +
    `Service-Worker-Allowed` +
    + Indicates the user agent will override the path restriction, which limits the maximum allowed scope url that the script can control, to the given value. +

    The value is a URL. If a relative URL is given, it is parsed against the script’s URL.

    +
    +
    + Default scope: +
    // Maximum allowed scope defaults to the path the script sits in
    +// "/js" in this example
    +navigator.serviceWorker.register("/js/sw.js").then(function() {
    +  console.log("Install succeeded with the default scope '/js'.");
    +});
    +
    +
    + Upper path without Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response has no Service-Worker-Allowed header
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed due to the path restriction violation.");
    +});
    +
    +
    + Upper path with Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /"
    +navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(function() {
    +  console.log("Install succeeded as the max allowed scope was overriden to '/'.");
    +});
    +
    +
    + A path restriction voliation even with Service-Worker-Allowed header: +
    // Set the scope to an upper path of the script location
    +// Response included "Service-Worker-Allowed : /foo"
    +navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(function() {
    +  console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
    +});
    +
    +
    +
    +

    Syntax

    +

    ABNF for the values of the headers used by the service worker’s script resource requests and responses:

    +
    Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
    +
    +

    The validation of the Service-Worker-Allowed header’s values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.

    +
    +
    +
    +

    9. Acknowledgements

    +

    Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day’s discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress.

    +

    Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson’s rigorous Web Worker spec. Much thanks to him.

    +

    In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref and Jinho Bang.

    +

    Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process.

    +

    The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance.

    +

    Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.

    +
    +
    +
    +

    Conformance

    +

    Document conventions

    +

    Conformance requirements are expressed with a combination of + descriptive assertions and RFC 2119 terminology. The key words “MUST”, + “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, + “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this + document are to be interpreted as described in RFC 2119. + However, for readability, these words do not appear in all uppercase + letters in this specification.

    +

    All of the text of this specification is normative except sections + explicitly marked as non-normative, examples, and notes. [RFC2119]

    +

    Examples in this specification are introduced with the words “for example” + or are set apart from the normative text with class="example", + like this:

    +
    + +

    This is an example of an informative example.

    +
    +

    Informative notes begin with the word “Note” and are set apart from the + normative text with class="note", like this:

    +

    Note, this is an informative note.

    +

    Conformant Algorithms

    +

    Requirements phrased in the imperative as part of algorithms (such as + "strip any leading space characters" or "return false and abort these + steps") are to be interpreted with the meaning of the key word ("must", + "should", "may", etc) used in introducing the algorithm.

    +

    Conformance requirements phrased as algorithms or specific steps can be + implemented in any manner, so long as the end result is equivalent#dfn-processing-equivalenceReferenced in:3.1.3. postMessage(message, transfer)3.2.1. installing3.2.2. waiting3.2.3. active3.2.5. update()3.2.6. unregister()3.4.1. controller3.4.2. ready (2)3.4.3. register(scriptURL, options)3.4.4. getRegistration(clientURL)3.4.5. getRegistrations()4.1.3. skipWaiting() (2)4.2.4. postMessage(message, transfer)4.2.7. focus() (2)4.2.8. navigate(url) (2)4.3.1. get(id) (2) (3)4.3.2. matchAll(options) (2) (3) (4) (5)4.3.3. openWindow(url) (2)4.3.4. claim()4.4.1. event.waitUntil(f) (2)4.5.4. event.respondWith(r)5.4.1. match(request, options)5.4.2. matchAll(request, options)5.4.3. add(request)5.4.4. addAll(requests)5.4.5. put(request, response)5.4.6. delete(request, options)5.4.7. keys(request, options)5.5.1. match(request, options)5.5.2. has(cacheName)5.5.3. open(cacheName)5.5.4. delete(cacheName)5.5.5. keys()8.4. Request Functional Event DispatchRegisterUpdateInstall (2)Handle Fetch (2) (3) (4)Handle Functional EventHandle Service Worker Client Unload (2). In + particular, the algorithms defined in this specification are intended to + be easy to understand and are not intended to be performant. Implementers + are encouraged to optimize.

    + +

    Index

    +

    Terms defined by this specification

    + +

    Terms defined by reference

    + +

    References

    +

    Normative References

    +
    +
    [CSP2] +
    Mike West; Adam Barth; Daniel Veditz. Content Security Policy Level 2. 21 July 2015. CR. URL: https://w3c.github.io/webappsec/specs/CSP2/ +
    [ECMA-262] +
    ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/ +
    [FETCH] +
    Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/ +
    [HTML] +
    Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/ +
    [WHATWG-DOM] +
    Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/ +
    [WHATWG-URL] +
    Anne van Kesteren; Sam Ruby. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/ +
    [WebIDL] +
    Cameron McCormack; Boris Zbarsky. WebIDL Level 1. 4 August 2015. WD. URL: https://heycam.github.io/webidl/ +
    [PAGE-VISIBILITY] +
    Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: http://www.w3.org/TR/page-visibility/ +
    [POWERFUL-FEATURES] +
    Mike West; Yan Zhu. Privileged Contexts. 24 April 2015. WD. URL: https://w3c.github.io/webappsec/specs/powerfulfeatures/ +
    [PROMISES-GUIDE] +
    Writing Promise-Using Specifications. 24 July 2015. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/promises-guide +
    [QUOTA-API] +
    Kinuko Yasuda. Quota Management API. 15 December 2015. WD. URL: http://www.w3.org/TR/quota-api/ +
    [RFC2119] +
    S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119 +
    [RFC5234] +
    D. Crocker, Ed.; P. Overell. Augmented BNF for Syntax Specifications: ABNF. January 2008. Internet Standard. URL: https://tools.ietf.org/html/rfc5234 +
    [RFC7230] +
    R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing. June 2014. Proposed Standard. URL: https://tools.ietf.org/html/rfc7230 +
    [RFC7231] +
    R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content. June 2014. Proposed Standard. URL: https://tools.ietf.org/html/rfc7231 +
    +

    Informative References

    +
    +
    [WHATWG-NOTIFICATIONS] +
    Anne van Kesteren. Notifications API Standard. Living Standard. URL: https://notifications.spec.whatwg.org/ +
    [UNSANCTIONED-TRACKING] +
    Unsanctioned Web Tracking. 17 July 2015. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/unsanctioned-tracking +
    +

    IDL Index

    +
    [Exposed=(Window,Worker)]
    +interface ServiceWorker : EventTarget {
    +  readonly attribute USVString scriptURL;
    +  readonly attribute ServiceWorkerState state;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +
    +  // event
    +  attribute EventHandler onstatechange;
    +};
    +ServiceWorker implements AbstractWorker;
    +
    +enum ServiceWorkerState {
    +  "installing",
    +  "installed",
    +  "activating",
    +  "activated",
    +  "redundant"
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface ServiceWorkerRegistration : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? installing;
    +  [Unforgeable] readonly attribute ServiceWorker? waiting;
    +  [Unforgeable] readonly attribute ServiceWorker? active;
    +
    +  readonly attribute USVString scope;
    +
    +  [NewObject] Promise<void> update();
    +  [NewObject] Promise<boolean> unregister();
    +
    +  // event
    +  attribute EventHandler onupdatefound;
    +};
    +
    +partial interface Navigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +partial interface WorkerNavigator {
    +  [SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface ServiceWorkerContainer : EventTarget {
    +  [Unforgeable] readonly attribute ServiceWorker? controller;
    +  [SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
    +
    +  [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);
    +
    +  [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
    +  [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
    +
    +
    +  // events
    +  attribute EventHandler oncontrollerchange;
    +  attribute EventHandler onerror;
    +  attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
    +};
    +
    +dictionary RegistrationOptions {
    +  USVString scope;
    +};
    +
    +[Constructor(DOMString type, optional ServiceWorkerMessageEventInit eventInitDict), Exposed=(Window,Worker)]
    +interface ServiceWorkerMessageEvent : Event {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +dictionary ServiceWorkerMessageEventInit : EventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +[Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
    +interface ServiceWorkerGlobalScope : WorkerGlobalScope {
    +  // A container for a list of Client objects that correspond to
    +  // browsing contexts (or shared workers) that are on the origin of this SW
    +  [SameObject] readonly attribute Clients clients;
    +  [SameObject] readonly attribute ServiceWorkerRegistration registration;
    +
    +  [NewObject] Promise<void> skipWaiting();
    +
    +  attribute EventHandler oninstall;
    +  attribute EventHandler onactivate;
    +  attribute EventHandler onfetch;
    +
    +  // event
    +  attribute EventHandler onmessage; // event.source of the message events is Client object
    +
    +  // close() method inherited from WorkerGlobalScope should not be accessible.
    +};
    +
    +[Exposed=ServiceWorker]
    +interface Client {
    +  readonly attribute USVString url;
    +  readonly attribute FrameType frameType;
    +  readonly attribute DOMString id;
    +  void postMessage(any message, optional sequence<Transferable> transfer);
    +};
    +
    +[Exposed=ServiceWorker]
    +interface WindowClient : Client {
    +  readonly attribute VisibilityState visibilityState;
    +  readonly attribute boolean focused;
    +  [NewObject] Promise<WindowClient> focus();
    +  [NewObject] Promise<WindowClient> navigate(USVString url);
    +};
    +
    +enum FrameType {
    +  "auxiliary",
    +  "top-level",
    +  "nested",
    +  "none"
    +};
    +
    +[Exposed=ServiceWorker]
    +interface Clients {
    +  // The objects returned will be new instances every time
    +  [NewObject] Promise<any> get(DOMString id);
    +  [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
    +  [NewObject] Promise<WindowClient?> openWindow(USVString url);
    +  [NewObject] Promise<void> claim();
    +};
    +
    +dictionary ClientQueryOptions {
    +  boolean includeUncontrolled = false;
    +  ClientType type = "window";
    +};
    +
    +enum ClientType {
    +  "window",
    +  "worker",
    +  "sharedworker",
    +  "all"
    +};
    +
    +[Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableEvent : Event {
    +  void waitUntil(Promise<any> f);
    +};
    +
    +dictionary ExtendableEventInit : EventInit {
    +  // Defined for the forward compatibility across the derived events
    +};
    +
    +[Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
    +interface FetchEvent : ExtendableEvent {
    +  [SameObject] readonly attribute Request request;
    +  readonly attribute DOMString? clientId;
    +  readonly attribute boolean isReload;
    +
    +  void respondWith(Promise<Response> r);
    +};
    +
    +dictionary FetchEventInit : ExtendableEventInit {
    +  required Request request;
    +  DOMString? clientId = null;
    +  boolean isReload = false;
    +};
    +
    +[Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
    +interface ExtendableMessageEvent : ExtendableEvent {
    +  readonly attribute any data;
    +  readonly attribute DOMString origin;
    +  readonly attribute DOMString lastEventId;
    +  [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
    +  [SameObject] readonly attribute MessagePort[]? ports;
    +};
    +
    +dictionary ExtendableMessageEventInit : ExtendableEventInit {
    +  any data;
    +  DOMString origin;
    +  DOMString lastEventId;
    +  (Client or ServiceWorker or MessagePort)? source;
    +  sequence<MessagePort>? ports;
    +};
    +
    +partial interface Window {
    +  [SameObject] readonly attribute CacheStorage caches;
    +};
    +
    +partial interface WorkerGlobalScope {
    +  [SameObject] readonly attribute CacheStorage caches;
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface Cache {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<void> add(RequestInfo request);
    +  [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
    +  [NewObject] Promise<void> put(RequestInfo request, Response response);
    +  [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
    +};
    +
    +dictionary CacheQueryOptions {
    +  boolean ignoreSearch = false;
    +  boolean ignoreMethod = false;
    +  boolean ignoreVary = false;
    +  DOMString cacheName;
    +};
    +
    +dictionary CacheBatchOperation {
    +  DOMString type;
    +  Request request;
    +  Response response;
    +  CacheQueryOptions options;
    +};
    +
    +[Exposed=(Window,Worker)]
    +interface CacheStorage {
    +  [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
    +  [NewObject] Promise<boolean> has(DOMString cacheName);
    +  [NewObject] Promise<Cache> open(DOMString cacheName);
    +  [NewObject] Promise<boolean> delete(DOMString cacheName);
    +  [NewObject] Promise<sequence<DOMString>> keys();
    +};
    +
    +
    +

    Issues Index

    +
    +
    The behavior of the attribute getter in non-secure contexts is in discussion.
    +
    These substeps will be replaced by using pipe when the algorithm for pipeTo becomes stable.
    +
    + \ No newline at end of file