Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
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.
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.
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.
This document relies on the following specifications:
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).
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.
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.
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.
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.
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.
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);
});
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).
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
".
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
"
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
"
The service worker in this state is considered a waiting worker.
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
"
The service worker in this state is considered an active worker ready to handle functional events.
redundant
"
A new service worker is replacing the current service worker, or the current service worker is being discarded due to an install failure.
id
The id
attribute must return the service worker's id.
postMessage(message, transfer)
The postMessage(message, transfer)
method must run these steps or their equivalent:
redundant
", throw an "InvalidStateError
" exception and abort these steps. DataCloneError
" exception and abort these steps.ServiceWorkerGlobalScope
object associated with serviceWorker.ExtendableMessageEvent
interface, with the event type message, which does not bubble, is not cancelable, and has no default action.ServiceWorkerGlobalScope
object, let the source attribute of e be initialized to a new ServiceWorker
object that represents globalObject's service worker.WindowClient
object that represents globalObject's browsing context.Client
object that represents globalObject's worker environment.The task must use the DOM manipulation task source.
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 |
statechange |
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).
installing
ServiceWorker
object that represents the service worker registration's installing worker.waiting
ServiceWorker
object that represents the service worker registration's waiting worker.active
ServiceWorker
object that represents the service worker registration's 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:
unregister()
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 |
updatefound |
navigator.serviceWorker
partial interface Navigator {
[SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};
partial interface WorkerNavigator {
[SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
};
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.
controller
ready
Implementers should consider this condition is met when the corresponding registration request gets to the step 10 of Activate algorithm.
ServiceWorkerRegistration
object, setting its service worker client to service worker client, which represents registration.register(scriptURL, options)
TypeError
../
" with scriptURL.
The scope url for the registration is set to the location of the service worker script by default.
TypeError
.getRegistration(clientURL)
TypeError
.SecurityError
" exception.ServiceWorkerRegistration
object, setting its service worker client to service worker client, which represents registration.undefined
.getRegistrations()
ServiceWorkerRegistration
object, setting its service worker client to service worker client, associated with entry.[[value]] to the array.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 handler | event handler event type |
---|---|
oncontrollerchange |
controllerchange |
onerror |
error |
onmessage |
message |
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.
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.
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.
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.
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.
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.
The following event is dispatched on ServiceWorker
object:
Event name | Interface | Dispatched when… |
---|---|---|
statechange |
Event |
The state attribute of the ServiceWorker object is changed. |
The following event is dispatched on ServiceWorkerRegistration
object:
Event name | Interface | Dispatched when… |
---|---|---|
updatefound |
Event |
The service worker registration's installing worker changes. (See step 8 of the Install algorithm). |
The following events are dispatched on ServiceWorkerContainer
object:
Event name | Interface | Dispatched when… |
---|---|---|
controllerchange |
Event |
The 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.) |
message |
ServiceWorkerMessageEvent |
When it receives a message. |
error |
ErrorEvent |
Any error occurred from the associated service workers. |
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");
})
);
});
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.
clients
clients
attribute must return the Clients
object.
registration
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:
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 handler | event handler event type |
---|---|
oninstall |
install |
onactivate |
activate |
onfetch |
fetch |
onmessage |
message |
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).
url
The url
attribute must return the context object's associated service worker client's serialized creation url.
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
"
The window client's global object's browsing context is an auxiliary browsing context.
top-level
"
The window client's global object's browsing context is a top-level browsing context.
nested
"
The window client's global object's browsing context is a nested browsing context.
none
"id
The id
attribute must return its associated service worker client's id.
postMessage(message, transfer)
The postMessage(message, transfer)
method must run these steps or their equivalent:
DataCloneError
" exception and abort these steps.ServiceWorkerContainer
object whose service worker client is the context object's service worker client.InvalidStateError
" exception.ServiceWorkerMessageEvent
interface, with the event type message, which does not bubble, is not cancelable, and has no default action.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.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.
visibilityState
The visibilityState
attribute must return the context object's visibility state.
focused
The focused
attribute must return the context object's focus state.
focus()
The focus()
method must run these steps or their equivalent:
InvalidAccessError
" exception.TypeError
.navigate(url)
TypeError
.about:blank
, return a promise rejected with a TypeError
.TypeError
.Document
, reject promise with a TypeError
and abort these steps.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.
matchAll(options)
The matchAll(options)
method must run these steps or their equivalent:
window
", and client is a window client, then:
worker
" and client is a dedicated worker client, add a Client
object that represents client to matchedClients.sharedworker
" and client is a shared worker client, add a Client
object that represents client to matchedClients.all
", then:
Client
object that represents client to matchedClients.openWindow(url)
The openWindow(url)
method must run these steps or their equivalent:
TypeError
.about:blank
, return a promise rejected with a TypeError
.InvalidAccessError
" exception.claim()
The claim()
method must run these steps or their equivalent:
InvalidStateError
" exception.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.
event.waitUntil(f)
waitUntil(f)
method extends the lifetime of the event.
waitUntil(f)
method must run these steps or their equivalent:
InvalidStateError
" exception.In the task task in which the steps of waitUntil(f)
is running, the user agent must run these steps or their equivalent:
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:
oninstall
, it delays treating the installing worker as installed (i.e. a waiting worker) until the passed promise f resolves successfully. If f rejects, the installation fails. (See step 11.6.2 of Install algorithm). 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.onactivate
, it delays treating the active worker as activated until the passed promise f settles. (See step 16 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, 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:
event.request
request
attribute must return the value it was initialized to.
event.client
client
attribute must return the value it was initialized to.
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.
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:
InvalidStateError
" exception.InvalidStateError
" exception.Response
object, then:
Response
object, then:
request
attribute value.opaque
", and request's associated request is a client request, 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.)
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.
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.
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.
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.
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.
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.
The following events are dispatched on ServiceWorkerGlobalScope object:
Event name | Interface | Dispatched 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] 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.) |
message |
ExtendableMessageEvent |
When it receives a message. |
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.
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.
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 {
[SameObject] 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 {
[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.)
match(request, options)
match(request, options)
method must run these steps or their equivalent:
matchAll(request, options)
method with request and options as the arguments.matchAll(request, options)
matchAll(request, options)
method must run these steps or their equivalent:
HEAD
` and options.ignoreMethod is false, set response's body to null.add(request)
add(request)
method must run these steps or their equivalent:
addAll(requests)
passing requests as the argument.addAll(requests)
addAll(requests)
method must run these steps or their equivalent:
http
" and "https
", then:
fetch
".TypeError
.Vary
`, then:
*
", set matchAsterisk to true and break the loop.TypeError
.This step ensures that the promise for this fetch resolves as soon as the response's headers become available.
CacheBatchOperation
dictionary.TypeError
.put(request, response)
put(request, response)
method must run these steps or their equivalent:
http
" and "https
", return a promise rejected with a TypeError
.Vary
`, then:
*
", return a promise rejected with a TypeError
.CacheBatchOperation
dictionary.TypeError
.delete(request, options)
delete(request, options)
method must run these steps or their equivalent:
CacheBatchOperation
dictionary.keys(request, options)
keys(request, options)
method must run these steps or their equivalent:
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.
match(request, options)
match(request, options)
method must run these steps or their equivalent:
Not Secure
, return a new promise rejected with a "SecurityError
" exception.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)
.)NotFoundError
" exception.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)
.)has(cacheName)
has(cacheName)
method must run these steps or their equivalent:
Not Secure
, return a new promise rejected with a "SecurityError
" exception.open(cacheName)
open(cacheName)
method must run these steps or their equivalent:
Not Secure
, return a new promise rejected with a "SecurityError
" exception.Cache
object which is a copy of entry.[[value]].Cache
object.QuotaExceededError
" exception and abort these steps.delete(cacheName)
delete(cacheName)
method must run these steps or their equivalent:
Not Secure
, return a new promise rejected with a "SecurityError
" exception.has(cacheName)
method with cacheName as the argument.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.
Not Secure
, return a new promise rejected with a "SecurityError
" exception.Service workers should be implemented to be HTTPS-only. The reasons for SSL-only support include:
The section will be updated.
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.
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):
NetworkError
" exception.The following steps, or their equivalent, must be run at the end (as a part) of the step 6.1 of importScripts(urls):
The following step, or its equivalent, must be run as the step 7 of importScripts(urls):
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 Cache
s 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
". Response
s typed "opaque
" provide a much less expressive API than Response
s 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 Response
s typed "basic
", but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing Cache
s to store them allows applications to avoid re-architecting in most cases.
The section will be updated.
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.
Service workers are extensible from other specifications.
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);
};
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
};
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;
};
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.
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.
Not Trusted
, then:
SecurityError
" exception.SecurityError
" exception.SecurityError
" exception.ServiceWorkerRegistration
object, setting its service worker client to client, which represents registration.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.
Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.
Service-Worker
`/`script
` to r's header list.manual
".TypeError
.text/javascript
, application/x-javascript
, and application/javascript
, then:
SecurityError
" exception.Service-Worker-Allowed
` in response's header list.TypeError
./
" 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 "/
"./
" concatenated with the strings in maxScope's path (including empty strings), separated from each other by "/
"./
" concatenated with the strings in scopeURL's path (including empty strings), separated from each other by "/
".SecurityError
" exception.ServiceWorkerRegistration
object, setting its service worker client to client, which represents registration.The user agent may call this as often as it likes to check for updates.
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.
Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.
ServiceWorkerRegistration
object, setting its service worker client to client, which represents registration.updatefound
at all the ServiceWorkerRegistration
objects that represent registration for all the service worker clients whose creation url matches registration's scope url.ExtendableEvent
interface, with the event type install
, which does not bubble, is not cancelable, and has no default action.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.
Wait is a blocking wait. Implementers may use a condition variable or its equivalent synchronization primitive.
Resources will now use the service worker registration instead of the existing application cache.
ExtendableEvent
interface, with the event type activate
, which does not bubble, is not cancelable, and has no default action.ServiceWorkerGlobalScope
object.ServiceWorkerGlobalScope
object is defined as the service worker environment, which is a type of worker environments.)The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.
Request
object associated with request.serviceworker
".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.
iframe
" and request's url is local, then:
From this point, the service worker client starts to use its active worker's containing service worker registration.
FetchEvent
interface, with the event type fetch
, which does not bubble, is not cancelable, and has no default action.Client
object that represents request's client.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.respondWith(r)
method arg is a Response
object, then:
If task is discarded or the script has been aborted by the termination of activeWorker, set handleFetchFailed to true.
The task must use the DOM manipulation task source.
The user agent must run these steps, or their equivalent, when a service worker client unloads by unloading, being killed, or terminating.
SecurityError
" exception.ServiceWorker
objects associated with worker.statechange
at serviceWorker.The task must use serviceWorker's service worker client's responsible event loop and the DOM manipulation task source.
controllerchange
at the ServiceWorkerContainer
object client is associated with.The task must use client's responsible event loop and the DOM manipulation task source.
WindowClient
object that represents browsingContext.Request
objectCacheQueryOptions
object, optionalRequest
, Response
] pairs as its elements, optionalRequest
, Response
] pairs as its elementsGET
" nor "HEAD
", then:
Vary
`, or options.ignoreVary is true, then:
CacheBatchOperation
dictionary objectsResponse
objects.TypeError
.TypeError
.InvalidStateError
" exception.TypeError
.http
" and "https
", then:
TypeError
.GET
`, then:
TypeError
.TypeError
.The cache commit is allowed as long as the response's headers are available.
QuotaExceededError
" exception.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.