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 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 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 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 global object (a ServiceWorkerGlobalScope
object or null).
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 policy container (a policy container). It is initially a new policy container.
A service worker has an associated script resource map which is an responses.
A service worker has an associated set of used scripts (a set.
Note: The set of used scripts is only used to prune unused resources from a new worker’s map after installation, that were populated based on the old worker’s map during the update check.
A service worker has an associated skip waiting flag. Unless stated otherwise it is unset.
A service worker has an associated classic scripts imported flag. It is initially unset.
A service worker has an associated set of event types to handle (a set.
A service worker has an associated set of extended events (a set.
A service worker has an associated start status which can be null or a Completion. It is initially null.
A service worker has an associated all fetch listeners are empty flag. It is initially unset.
A service worker has an associated list of router rules (a list.
A service worker is said to be running if its event loop is running.
A service worker has an associated [[service worker queue]] (a parallel queue).
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.1.2. Events
The Service Workers specification defines service worker events (each of which is an event) that include (see the list):
2.2. Service Worker Timing
Service workers mark certain points in time that are later exposed by the navigation timing API.
A service worker timing info is a items:
- start time
-
A
DOMHighResTimeStamp
, initially 0. - fetch event dispatch time
-
A
DOMHighResTimeStamp
, initially 0.
2.3. Service Worker Registration
A service worker registration is a tuple of a scope url, a storage key, 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 storage key (a storage key).
A service worker registration has an associated scope url (a URL).
A service worker registration has an associated installing worker (a service worker or null) whose state is "installing
". It is initially set to null.
A service worker registration has an associated waiting worker (a service worker or null) whose state is "installed
". It is initially set to null.
A service worker registration has an associated active worker (a service worker or null) 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 is said to be stale if the registration’s last update check time is non-null and the time difference in seconds calculated by the current time minus the registration’s last update check time is greater than 86400.
A service worker registration has an associated update via cache mode, which is "imports
", "all
", or "none
". It is initially set to "imports
".
A service worker registration has one or more task queues that back up the tasks to the service worker registration’s task queues when the active worker is terminated and task queues owned by event loops in and of itself.
A service worker registration has an associated NavigationPreloadManager
object.
A service worker registration has an associated navigation preload enabled flag. It is initially unset.
A service worker registration has an associated navigation preload header value, which is a byte sequence. It is initially set to `true
`.
A service worker registration is said to be unregistered if registration map[this service worker registration’s (storage key, serialized scope url)] is not this service worker registration.
2.3.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 registration map that stores the entries of the tuple of service worker registration’s (storage key, serialized 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.4. Service Worker Client
A service worker client is an environment.
A service worker client has an associated discarded flag. It is initially unset.
Each service worker client has the following environment discarding steps:
-
Set client’s discarded flag.
Note: Implementations can discard clients whose discarded flag is set.
A service worker client has an algorithm defined as the origin that returns the service worker client’s origin otherwise.
A window client is a service worker client whose Window object.
A dedicated worker client is a service worker client whose DedicatedWorkerGlobalScope object.
A shared worker client is a service worker client whose SharedWorkerGlobalScope object.
A worker client is either a dedicated worker client or a shared worker client.
2.5. Control and Use
A service worker client has an active service worker. When a service worker client is controlled by a service worker, it is said that the service worker client is using the service worker’s containing service worker registration. A service worker client’s active service worker is determined as explained in the following subsections.
The rest of the section is non-normative.
The behavior in this section is not fully specified yet and will be specified in pull request.
2.5.1. The window client case
A window client is navigates.
When a window client is creation:
If the opaque origin, the window client’s active service worker is set to null. Otherwise, it is set to the creator active service worker.
When a window client is navigation:
If the active service worker is set to the result of the service worker registration matching. Otherwise, if the created same as its creator active service worker is set to null. Otherwise, it is set to the creator active service worker.
Note: For an initial replacement created is reused, but the active service worker is determined by the same behavior as above.
Note: origin is an opaque origin.
2.5.2. The worker client case
A worker client is runs a worker.
When the worker client is created:
When the active service worker is set to the result of the service worker registration matching. Otherwise, if the worker client’s origin is an blob URL and the worker client’s origin is not the global object’s active service worker is set to null. Otherwise, it is set to the global object’s owner set.
Note: Window clients and worker clients with a opaque origin. Window clients and worker clients with a request’s document or owner, the active service worker is set to null.
2.6. Task Sources
The following additional task sources are used by service workers.
- The handle fetch task source
-
This dispatching
fetch
events to service workers. - The handle functional event task source
-
This push events, to service workers.
Note: 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.
2.7. User Agent Shutdown
A user agent must maintain the state of its stored service worker registrations across restarts with the following rules:
-
An installing worker does not persist but is discarded. If the installing worker was the only service worker for the service worker registration, the service worker registration is discarded.
-
A waiting worker promotes to an active worker.
To attain this, the user agent must invoke Handle User Agent Shutdown when it terminates.
3. Client Context
/ scope defaults to the path the script sits in / "/" in this example navigator. serviceWorker. register( "/serviceworker.js" ). then( registration=> { console. log( "success!" ); if ( registration. installing) { registration. installing. postMessage( "Howdy from your installing page." ); } }, err=> { console. error( "Installing the worker failed!" , err); });
3.1. ServiceWorker
[Exposed =(Window ,Worker )]interface :
ServiceWorker EventTarget {readonly attribute USVString scriptURL ;readonly attribute ServiceWorkerState state ;object >);
transfer StructuredSerializeOptions = {}); / event
options attribute EventHandler onstatechange ; };ServiceWorker includes AbstractWorker ;enum {
ServiceWorkerState ,
"parsed" ,
"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 documents and workers 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. Getting ServiceWorker
instances
An values are ServiceWorker
objects.
-
Let objectMap be environment’s service worker object map.
-
If objectMap[serviceWorker] does not exist, then:
-
Let serviceWorkerObj be a new
ServiceWorker
in environment’s Realm, and associate it with serviceWorker. -
Set objectMap[serviceWorker] to serviceWorkerObj.
-
-
Return objectMap[serviceWorker].
3.1.2. scriptURL
The scriptURL
getter steps are to return the service worker’s serialized script url.
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" );
The value of navigator.serviceWorker.controller.scriptURL
will be "https://example.com/service_worker.js
".
3.1.3. state
The state
attribute must return the value (in ServiceWorkerState
enumeration) to which it was last set.
3.1.4. postMessage(message, transfer)
The postMessage(message, transfer)
method steps are:
-
Let options be «[ "transfer" → transfer ]».
-
Invoke
postMessage(message, options)
with message and options as the arguments.
3.1.5. postMessage(message, options)
The postMessage(message, options)
method steps are:
-
Let serviceWorker be the service worker represented by this.
-
Let incumbentSettings be the incumbent settings object.
-
Let incumbentGlobal be incumbentSettings’s global object.
-
Let serializeWithTransferResult be transfer"]). Rethrow any exceptions.
-
If the result of running the Should Skip Event algorithm with "message" and serviceWorker is true, then return.
-
Run these substeps in parallel:
-
If the result of running the Run Service Worker algorithm with serviceWorker is failure, then return.
-
DOM manipulation task source to run the following steps:
-
Let source be determined by switching on the type of incumbentGlobal:
ServiceWorkerGlobalScope
- The result of getting the service worker object that represents incumbentGlobal’s service worker in the relevant settings object of serviceWorker’s global object.
Window
- a new
WindowClient
object that represents incumbentGlobal’s relevant settings object. - Otherwise
- a new
Client
object that represents incumbentGlobal’s associated worker
-
Let origin be the origin.
-
Let destination be the
ServiceWorkerGlobalScope
object associated with serviceWorker. -
Let deserializeRecord be Realm).
If this throws an exception, let e be the result of creating an event named
messageerror
, usingExtendableMessageEvent
, with theorigin
attribute initialized to origin and thesource
attribute initialized to source. -
Else:
-
Let messageClone be deserializeRecord.[[Deserialized]].
-
Let newPorts be a new MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.
-
Let e be the result of creating an event named
message
, usingExtendableMessageEvent
, with theorigin
attribute initialized to origin, thesource
attribute initialized to source, thedata
attribute initialized to messageClone, and theports
attribute initialized to newPorts.
-
-
Dispatch e at destination.
-
Invoke Update Service Worker Extended Events Set with serviceWorker and e.
-
-
3.1.6. Event handler
The following is the event handler IDL attributes, by all objects implementing ServiceWorker
interface:
event handler | event handler event type |
---|---|
onstatechange
| statechange
|
3.2. ServiceWorkerRegistration
[Exposed =(Window ,Worker )]interface :
ServiceWorkerRegistration EventTarget {readonly attribute ServiceWorker ?installing ;readonly attribute ServiceWorker ?waiting ;readonly attribute ServiceWorker ?active ; [SameObject ]readonly attribute NavigationPreloadManager navigationPreload ;readonly attribute USVString scope ;readonly attribute ServiceWorkerUpdateViaCache updateViaCache ; [undefined >update (); [boolean >unregister (); / eventattribute EventHandler onupdatefound ; };enum {
ServiceWorkerUpdateViaCache ,
"imports" ,
"all" };
"none"
A ServiceWorkerRegistration
has a service worker registration (a service worker registration).
3.2.1. Getting ServiceWorkerRegistration
instances
An values are ServiceWorkerRegistration
objects.
-
Let objectMap be environment’s service worker registration object map.
-
If objectMap[registration] does not exist, then:
-
Let registrationObject be a new
ServiceWorkerRegistration
in environment’s Realm. -
Set registrationObject’s service worker registration to registration.
-
Set registrationObject’s
installing
attribute to null. -
Set registrationObject’s
waiting
attribute to null. -
Set registrationObject’s
active
attribute to null. -
If registration’s installing worker is not null, then set registrationObject’s
installing
attribute to the result of getting the service worker object that represents registration’s installing worker in environment. -
If registration’s waiting worker is not null, then set registrationObject’s
waiting
attribute to the result of getting the service worker object that represents registration’s waiting worker in environment. -
If registration’s active worker is not null, then set registrationObject’s
active
attribute to the result of getting the service worker object that represents registration’s active worker in environment. -
Set objectMap[registration] to registrationObject.
-
-
Return objectMap[registration].
3.2.2. installing
installing
attribute must return the value to which it was last set.
Note: Within a Realm, there is only one ServiceWorker
object per associated service worker.
3.2.3. waiting
waiting
attribute must return the value to which it was last set.
Note: Within a Realm, there is only one ServiceWorker
object per associated service worker.
3.2.4. active
active
attribute must return the value to which it was last set.
Note: Within a Realm, there is only one ServiceWorker
object per associated service worker.
3.2.5. navigationPreload
The navigationPreload
getter steps are to return the service worker registration’s NavigationPreloadManager
object.
3.2.6. scope
The scope
getter steps are to return the service worker registration’s serialized scope url.
registration.scope
, obtained from navigator.serviceWorker.ready.then(registration => console.log(registration.scope))
for example, will be "https://example.com/
". 3.2.7. updateViaCache
The updateViaCache
getter steps are to return the service worker registration’s update via cache mode.
3.2.8. update()
The update()
method steps are:
-
Let registration be the service worker registration.
-
Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
-
If newestWorker is null, return DOMException and abort these steps.
-
If InvalidStateError"
DOMException
and abort these steps. -
Let promise be a promise.
-
Let job be the result of running Create Job with update, registration’s storage key, registration’s scope url, newestWorker’s script url, promise, and relevant settings object.
-
Set job’s worker type to newestWorker’s type.
-
Invoke Schedule Job with job.
-
Return promise.
3.2.9. unregister()
Note: The unregister()
method unregisters the service worker registration. It is important to note that the currently controlled service worker client’s navigations.
The unregister()
method steps are:
-
Let registration be the service worker registration.
-
Let promise be a new promise.
-
Let job be the result of running Create Job with unregister, registration’s storage key, registration’s scope url, null, promise, and relevant settings object.
-
Invoke Schedule Job with job.
-
Return promise.
3.2.10. Event handler
The following is the event handler IDL attributes, by all objects implementing ServiceWorkerRegistration
interface:
event handler | event handler event type |
---|---|
onupdatefound
| updatefound
|
3.3. navigator.serviceWorker
partial interface Navigator { [SameObject ]readonly attribute ServiceWorkerContainer serviceWorker ; };partial interface WorkerNavigator { [SameObject ]readonly attribute ServiceWorkerContainer serviceWorker ; };
The serviceWorker
getter steps are to return the ServiceWorkerContainer
object that is associated with this.
3.4. ServiceWorkerContainer
[Exposed =(Window ,Worker )]interface :
ServiceWorkerContainer EventTarget {readonly attribute ServiceWorker ?controller ;readonly attribute Promise <ServiceWorkerRegistration >ready ; [USVString ),
scriptURL optional RegistrationOptions = {}); [
options USVString = ""); [
clientURL FrozenArray <ServiceWorkerRegistration >>getRegistrations ();undefined startMessages (); / eventsattribute EventHandler oncontrollerchange ;attribute EventHandler onmessage ; / event.source of message events is ServiceWorker objectattribute EventHandler onmessageerror ; };
dictionary {
RegistrationOptions USVString ;
scope WorkerType = "classic";
type ServiceWorkerUpdateViaCache = "imports"; };
updateViaCache
The user agent must create a ServiceWorkerContainer
object when 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 WorkerNavigator object that the ServiceWorkerContainer
is retrieved from.
A ServiceWorkerContainer
object has an associated ready promise (a promise or null). It is initially null.
A ServiceWorkerContainer
object has a relevant global object is a relevant settings object’s associated document.
3.4.1. controller
controller
attribute must run these steps:
-
Let client be this’s service worker client.
-
If client’s active service worker is null, then return null.
-
Return the result of getting the service worker object that represents client’s relevant settings object.
Note: navigator.serviceWorker.controller
returns null
if the request is a force refresh (shift+refresh).
3.4.2. ready
ready
attribute must run these steps:
-
If a new promise.
-
Let readyPromise be this’s ready promise.
-
If readyPromise is pending, run the following substeps in parallel:
-
Let client by this’s service worker client.
-
Let storage key be the result of running obtain a storage key given client.
-
Let registration be the result of running Match Service Worker Registration given storage key and client’s creation URL.
-
If registration is not null, and registration’s active worker is not null, DOM manipulation task source, to resolve readyPromise with the result of getting the service worker registration object that represents registration in readyPromise’s relevant settings object.
-
-
Return readyPromise.
Note: The returned ready promise will never reject. If it does not resolve in this algorithm, it will eventually resolve when a matching service worker registration is registered and its active worker is set. (See the relevant Activate algorithm step.)
3.4.3. register(scriptURL, options)
Note: 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.
The register(scriptURL, options)
method steps are:
-
Let p be a promise.
-
Set scriptURL to the result of invoking relevant global object, scriptURL, "ServiceWorkerContainer register", and "script".
-
Let client be this’s service worker client.
-
Let scriptURL be the result of API base URL.
-
Let scopeURL be null.
-
If options["
scope
"] relevant settings object’s API base URL. -
Invoke Start Register with scopeURL, scriptURL, p, client’s creation URL, options["
type
"], and options["updateViaCache
"]. -
Return p.
3.4.4. getRegistration(clientURL)
getRegistration(clientURL)
method steps are:
-
Let client be this’s service worker client.
-
Let storage key be the result of running obtain a storage key given client.
-
Let clientURL be the result of API base URL.
-
If clientURL is failure, return a promise rejected with a
TypeError
. -
Set clientURL’s fragment to null.
-
If the DOMException.
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
Let registration be the result of running Match Service Worker Registration given storage key and clientURL.
-
If registration is null, resolve promise with undefined and abort these steps.
-
Resolve promise with the result of getting the service worker registration object that represents registration in promise’s relevant settings object.
-
-
Return promise.
3.4.5. getRegistrations()
getRegistrations()
method steps are:
-
Let client be this’s service worker client.
-
Let client storage key be the result of running obtain a storage key given client.
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let registrations be a new list.
-
For each (storage key, scope) → registration of registration map:
-
If storage key append registration to registrations.
-
-
DOM manipulation task source, to run the following steps:
-
Let registrationObjects be a new list.
-
For each registration of registrations:
-
Let registrationObj be the result of getting the service worker registration object that represents registration in promise’s relevant settings object.
-
Append registrationObj to registrationObjects.
-
-
Resolve promise with relevant Realm.
-
-
-
Return promise.
3.4.6. startMessages()
The startMessages()
method steps are to enable this’s client message queue if it is not enabled.
3.4.7. Event handlers
The following are the event handler IDL attributes, by all objects implementing the ServiceWorkerContainer
interface:
event handler | event handler event type |
---|---|
oncontrollerchange
| controllerchange
|
onmessage
| message
|
onmessageerror
| messageerror
|
The first time the onmessage
setter steps are performed, enable this’s client message queue.
3.5. Events
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 service 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
| Event
| The service worker client receives a message from a service worker. See postMessage(message, options) .
|
messageerror
| Event
| The service worker client is sent a message that cannot be deserialized from a service worker. See postMessage(message, options) .
|
3.6. NavigationPreloadManager
[Exposed =(Window ,Worker )]interface {
NavigationPreloadManager undefined >enable ();undefined >disable ();ByteString );
value Promise <NavigationPreloadState >getState (); };dictionary {
NavigationPreloadState boolean =
enabled false ;ByteString ; };
headerValue
3.6.1. enable()
The enable()
method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let registration be this’s associated service worker registration.
-
If registration’s active worker is null, DOMException, and abort these steps.
-
Set registration’s navigation preload enabled flag.
-
Resolve promise with undefined.
-
-
Return promise.
3.6.2. disable()
The disable()
method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let registration be this’s associated service worker registration.
-
If registration’s active worker is null, DOMException, and abort these steps.
-
Unset registration’s navigation preload enabled flag.
-
Resolve promise with undefined.
-
-
Return promise.
3.6.3. setHeaderValue(value)
The setHeaderValue(value)
method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let registration be this’s associated service worker registration.
-
If registration’s active worker is null, DOMException, and abort these steps.
-
Set registration’s navigation preload header value to value.
-
Resolve promise with undefined.
-
-
Return promise.
3.6.4. getState()
The getState()
method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let registration be this’s associated service worker registration.
-
Let state be a new
NavigationPreloadState
dictionary. -
If registration’s navigation preload enabled flag is set, set state["
enabled
"] to true. -
Set state["
headerValue
"] to registration’s navigation preload header value. -
Resolve promise with state.
-
-
Return promise.
4. Execution Context
/ caching.js self. addEventListener( "install" , event=> { event. waitUntil( / Open a cache of resources. caches. open( "shell-v1" ). then( cache=> { / Begins the process of fetching them. Succeeds only once all / resources have been stored. Even just one failing resource / causes the entire operation to fail. return cache. addAll([ "/app.html" , "/assets/v1/base.css" , "/assets/v1/app.js" , "/assets/v1/logo.png" , "/assets/v1/intro_video.webm" ]); }) ); }); self. addEventListener( "fetch" , event=> { / 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: event. respondWith( caches. match( e. request). then( response=> { return response|| fetch( e. request); }). catch (() => { return caches. match( "/fallback.html" ); }) ); });
4.1. ServiceWorkerGlobalScope
[SecureContext ]interface :
ServiceWorkerGlobalScope WorkerGlobalScope { [SameObject ]readonly attribute Clients clients ; [SameObject ]readonly attribute ServiceWorkerRegistration registration ; [SameObject ]readonly attribute ServiceWorker serviceWorker ; [undefined >skipWaiting ();attribute EventHandler oninstall ;attribute EventHandler onactivate ;attribute EventHandler onfetch ;attribute EventHandler onmessage ;attribute EventHandler onmessageerror ; };
A ServiceWorkerGlobalScope
object represents the global execution context of a service worker.
A ServiceWorkerGlobalScope
object has an associated service worker (a service worker).
A ServiceWorkerGlobalScope
object has an associated force bypass cache for import scripts flag. It is initially unset.
A ServiceWorkerGlobalScope
object has an associated race response map which is an values are race response.
A race response is a response, "pending
", or null.
Note: 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.
4.1.1. clients
The clients
getter steps are to return the Clients
object that is associated with this.
4.1.2. registration
The registration
getter steps are to return the result of getting the service worker registration object representing relevant settings object.
4.1.3. serviceWorker
The serviceWorker
getter steps are to return the result of getting the service worker object that represents relevant settings object.
4.1.4. skipWaiting()
Note: 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.
The skipWaiting()
method steps are:
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
Set service worker’s skip waiting flag.
-
Invoke Try Activate with service worker’s containing service worker registration.
-
Resolve promise with undefined.
-
-
Return promise.
4.1.5. Event handlers
The following are the 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
|
onmessageerror
| messageerror
|
4.2. Client
[Exposed =ServiceWorker ]interface {
Client readonly attribute USVString url ;readonly attribute FrameType frameType ;readonly attribute DOMString id ;readonly attribute ClientType type ;object >);
transfer StructuredSerializeOptions = {}); }; [
options Exposed =ServiceWorker ]interface :
WindowClient Client {readonly attribute VisibilityState visibilityState ;readonly attribute boolean focused ; [USVString >ancestorOrigins ; [Promise <WindowClient >focus (); [USVString ); };
url enum {
FrameType ,
"auxiliary" ,
"top-level" ,
"nested" };
"none"
A Client
object has an associated service worker client (a service worker client).
A Client
object has an associated frame type, which is one of "auxiliary
", "top-level
", "nested
", and "none
". Unless stated otherwise it is "none
".
A WindowClient
object has an associated browsing context, which is its service worker client’s browsing context.
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).
A WindowClient
object has an associated ancestor origins array.
4.2.1. url
The url
getter steps are to return creation URL.
4.2.2. frameType
The frameType
getter steps are to return this’s frame type.
4.2.3. id
The id
getter steps are to return id.
4.2.4. type
The type
getter steps are:
-
Let client be this’s service worker client.
-
If client is an environment settings object, then:
-
If client is a window client, return
"window"
. -
Else if client is a dedicated worker client, return
"worker"
. -
Else if client is a shared worker client, return
"sharedworker"
.
-
-
Else:
-
Return
"window"
.
-
4.2.5. postMessage(message, transfer)
The postMessage(message, transfer)
method steps are:
-
Let options be «[ "transfer" → transfer ]».
-
Invoke
postMessage(message, options)
with message and options as the arguments.
4.2.6. postMessage(message, options)
The postMessage(message, options)
method steps are:
-
Let contextObject be this.
-
Let sourceSettings be the contextObject’s relevant settings object.
-
Let serializeWithTransferResult be transfer"]). Rethrow any exceptions.
-
Run the following steps in parallel:
-
Let targetClient be null.
-
For each service worker client client:
-
If client is the contextObject’s service worker client, set targetClient to client, and break.
-
-
If targetClient is null, return.
-
Let destination be the
ServiceWorkerContainer
object whose associated service worker client is targetClient. -
Add a task that runs the following steps to destination’s client message queue:
-
Let origin be the origin.
-
Let source be the result of getting the service worker object that represents contextObject’s relevant global object’s service worker in targetClient.
-
Let deserializeRecord be relevant Realm).
If this throws an exception, catch it, source attribute initialized to source, and then abort these steps.
-
Let messageClone be deserializeRecord.[[Deserialized]].
-
Let newPorts be a new MessagePort objects in deserializeRecord.[[TransferredValues]], if any.
-
origin attribute initialized to origin, the
ports
attribute initialized to newPorts.
-
-
4.2.7. visibilityState
The visibilityState
getter steps are to return this’s visibility state.
4.2.8. focused
The focused
getter steps are to return this’s focus state.
4.2.9. ancestorOrigins
The ancestorOrigins
getter steps are to return this’s associated ancestor origins array.
4.2.10. focus()
The focus()
method steps are:
-
If no
promise rejected with an "
DOMException
. -
Let serviceWorkerEventLoop be the event loop.
-
Let promise be a new promise.
-
-
Run the this’s browsing context.
-
Let frameType be the result of running Get Frame Type with this’s browsing context.
-
Let visibilityState be visibilityState attribute value.
-
Let focusState be the result of running the active document.
-
Let ancestorOriginsList be Location object’s ancestor origins list’s associated list.
-
-
Let windowClient be the result of running Create Window Client with this’s associated service worker client, frameType, visibilityState, focusState, and ancestorOriginsList.
-
If windowClient’s focus state is true, resolve promise with windowClient.
-
Else, reject promise with a
TypeError
.
-
-
-
Return promise.
4.2.11. navigate(url)
The navigate(url)
method steps are:
-
Let url be the result of API base URL.
-
If url is failure, return a promise rejected with a
TypeError
. -
If url is
about:blank
, return a promise rejected with aTypeError
. -
If relevant global object’s service worker, return a promise rejected with a
TypeError
. -
Let serviceWorkerEventLoop be the event loop.
-
Let promise be a new promise.
-
-
Let browsingContext be this’s browsing context.
-
If browsingContext’s DOM manipulation task source, and abort these steps.
-
HandleNavigate: exceptionsEnabled true.
-
If the algorithm steps invoked in the step labeled HandleNavigate DOM manipulation task source, and abort these steps.
-
Let frameType be the result of running Get Frame Type with browsingContext.
-
Let visibilityState be browsingContext’s visibilityState attribute value.
-
Let focusState be the result of running the active document.
-
Let ancestorOriginsList be browsingContext’s ancestor origins list’s associated list.
-
-
If browsingContext’s
origin is not the origin, resolve promise with null and abort these steps.
-
Let windowClient be the result of running Create Window Client with this’s service worker client, frameType, visibilityState, focusState, and ancestorOriginsList.
-
Resolve promise with windowClient.
-
-
-
Return promise.
4.3. Clients
[Exposed =ServiceWorker ]interface { / The objects returned will be new instances every time [
Clients DOMString ); [
id FrozenArray <Client >>matchAll (optional ClientQueryOptions = {}); [
options USVString ); [
url undefined >claim (); };
dictionary {
ClientQueryOptions boolean =
includeUncontrolled false ;ClientType = "window"; };
type
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.
4.3.1. get(id)
The get(id)
method steps are:
-
Let promise be a new promise.
-
Run these substeps in parallel:
-
For each service worker client client where the result of running equals the associated service worker’s containing service worker registration’s storage key:
-
If client’s continue.
-
Wait for either client’s execution ready flag to be set or for client’s discarded flag to be set.
-
If client’s execution ready flag is set, then invoke Resolve Get Client Promise with client and promise, and abort these steps.
-
-
Resolve promise with undefined.
-
-
Return promise.
4.3.2. matchAll(options)
The matchAll(options)
method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let targetClients be a new list.
-
For each service worker client client where the result of running equals the associated service worker’s containing service worker registration’s storage key:
-
If client’s continue.
-
If client is not a continue.
-
If options["
includeUncontrolled
"] is false, and if client’s continue. -
Add client to targetClients.
-
-
Let matchedWindowData be a new list.
-
Let matchedClients be a new list.
-
For each service worker client client in targetClients:
-
If options["
type
"] is"window"
or"all"
, and client is not an environment settings object or is a window client, then:-
Let windowData be «[ "client" → client, "ancestorOriginsList" → a new list ]».
-
Let browsingContext be null.
-
Let isClientEnumerable be true.
-
If client is an browsing context.
-
Else, set browsingContext to client’s target browsing context.
-
-
If browsingContext has been discarded, then set isClientEnumerable to false and abort these steps.
-
If client is a window client and client’s active document, then set isClientEnumerable to false and abort these steps.
-
Set windowData["
frameType
"] to the result of running Get Frame Type with browsingContext. -
Set windowData["
visibilityState
"] to browsingContext’s visibilityState attribute value. -
Set windowData["
focusState
"] to the result of running the active document as the argument. -
If client is a window client, then set windowData["
ancestorOriginsList
"] to browsingContext’s ancestor origins list’s associated list.
-
-
Wait for task to have executed.
Note: Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken.
-
If isClientEnumerable is true, then:
-
Add windowData to matchedWindowData.
-
-
-
Else if options["
type
"] is"worker"
or"all"
and client is a dedicated worker client, or options["type
"] is"sharedworker"
or"all"
and client is a shared worker client, then:-
Add client to matchedClients.
-
-
-
-
Let clientObjects be a new list.
-
For each windowData in matchedWindowData:
-
Let windowClient be the result of running Create Window Client algorithm with windowData["
client
"], windowData["frameType
"], windowData["visibilityState
"], windowData["focusState
"], and windowData["ancestorOriginsList
"] as the arguments. -
Append windowClient to clientObjects.
-
-
For each client in matchedClients:
-
Let clientObject be the result of running Create Client algorithm with client as the argument.
-
Append clientObject to clientObjects.
-
-
Sort clientObjects such that:
-
WindowClient
objects whose browsing context has been focused order. -
WindowClient
objects whose browsing context has never been focused are placed next, sorted in their service worker client’s creation order. -
Client
objects whose associated service worker client is a worker client are placed next, sorted in their service worker client’s creation order.
Note: Window clients are always placed before worker clients.
-
-
Resolve promise with relevant Realm.
-
-
-
Return promise.
4.3.3. openWindow(url)
The openWindow(url)
method steps are:
-
Let url be the result of API base URL.
-
If url is failure, return a promise rejected with a
TypeError
. -
If url is
about:blank
, return a promise rejected with aTypeError
. -
If no
promise rejected with an "
DOMException
. -
Let serviceWorkerEventLoop be the event loop.
-
Let promise be a new promise.
-
Run these substeps in parallel:
-
Let newContext be a new top-level browsing context.
-
responsible event loop using the user interaction task source:
-
HandleNavigate: historyHandling "
replace
". -
If the algorithm steps invoked in the step labeled HandleNavigate DOM manipulation task source, and abort these steps.
-
Let frameType be the result of running Get Frame Type with newContext.
-
Let visibilityState be newContext’s visibilityState attribute value.
-
Let focusState be the result of running the active document as the argument.
-
Let ancestorOriginsList be newContext’s ancestor origins list’s associated list.
-
-
If the result of running equal to the service worker’s containing service worker registration’s storage key, then resolve promise with null and abort these steps.
-
Let client be the result of running Create Window Client with newContext’s
environment settings object, frameType, visibilityState, focusState, and ancestorOriginsList as the arguments.
-
Resolve promise with client.
-
-
-
-
Return promise.
4.3.4. claim()
The claim()
method steps are:
-
If the service worker is not an active worker, return a DOMException.
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
For each service worker client client where the result of running equals the service worker’s containing service worker registration’s storage key:
-
If client’s continue.
-
If client is not a continue.
-
Let storage key be the result of running obtain a storage key given client.
-
Let registration be the result of running Match Service Worker Registration given storage key and client’s creation URL.
-
If registration is not the service worker’s containing service worker registration, continue.
Note: registration will be null if the service worker’s containing service worker registration is unregistered.
-
If client’s active service worker is not the service worker, then:
-
Invoke Handle Service Worker Client Unload with client as the argument.
-
Set client’s active service worker to service worker.
-
Invoke Notify Controller Change algorithm with client as the argument.
-
-
-
Resolve promise with undefined.
-
-
Return promise.
4.4. ExtendableEvent
[Exposed =ServiceWorker ]interface :
ExtendableEvent Event {(
constructor DOMString ,
type optional ExtendableEventInit = {});
eventInitDict 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 an empty array.
An ExtendableEvent
object has an associated pending promises count (the number of pending promises in the extend lifetime promises). It is initially set to zero.
An ExtendableEvent
object has an associated timed out flag. It is initially unset, and is set after an optional user agent imposed delay if the pending promises count is greater than zero.
An ExtendableEvent
object is said to be active when its timed out flag is unset and either its pending promises count is greater than zero or its dispatch flag is set.
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)
Note: waitUntil()
method extends the lifetime of the event.
The waitUntil(f)
method steps are to add lifetime promise f to this.
ExtendableEvent
), run these steps:
-
If event’s
DOMException
. -
If event is not active, DOMException.
Note: If no lifetime extension promise has been added in the task that called the event handlers, calling
waitUntil()
in subsequent asynchronous tasks will throw. -
Add promise to event’s extend lifetime promises.
-
Increment event’s pending promises count by one.
Note: The pending promises count is incremented even if the given promise has already been settled. The corresponding count decrement is done in the microtask queued by the reaction to the promise.
-
Upon queue a microtask to run these substeps:
-
Decrement event’s pending promises count by one.
-
If event’s pending promises count is 0, then:
-
Let registration be the current global object’s associated service worker’s containing service worker registration.
-
If registration is unregistered, invoke Try Clear Registration with registration.
-
If registration is not null, invoke Try Activate with registration.
-
-
The user agent should not terminate a service worker if Service Worker Has No Pending Events returns false for that service worker.
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.
Note: Service workers delay treating the installing worker as "installed
" until all the promises in the activate
event’s extend lifetime promises settle. (See the relevant Activate algorithm step.) This is primarily used to ensure that any functional events are not dispatched to the service worker until it upgrades database schemas and deletes the outdated cache entries.
4.5. InstallEvent
[Exposed =ServiceWorker ]interface :
InstallEvent ExtendableEvent {(
constructor DOMString ,
type optional ExtendableEventInit = {});
eventInitDict sequence <RouterRule >)); };
rules dictionary {
RouterRule required RouterCondition ;
condition required RouterSource ; };
source dictionary {
RouterCondition URLPatternCompatible ;
urlPattern ByteString ;
requestMethod RequestMode ;
requestMode RequestDestination ;
requestDestination RunningStatus ;
runningStatus sequence <RouterCondition >;
_or RouterCondition ; };
not typedef (RouterSourceDict or RouterSourceEnum );
RouterSource dictionary {
RouterSourceDict DOMString ; };
cacheName enum {
RunningStatus ,
"running" };
"not-running" enum {
RouterSourceEnum ,
"cache" ,
"fetch-event" ,
"network" };
"race-network-and-fetch-handler"
A count router condition result is a struct that consists of:
-
A condition count (a number).
-
A quota exceeded (a boolean).
4.5.1. event.addRoutes(rules)
Note: addRoutes(rules)
registers rules for this service worker to offload simple tasks that the fetch event handler ordinarily does.
The addRoutes(rules)
method steps are:
-
If rules is a
RouterRule
dictionary, set rules to « rules ». -
Let serviceWorker be the current global object’s associated service worker.
-
For each rule of rules:
-
If running the Verify Router Condition algorithm with rule["
condition
"] and serviceWorker returns false, return TypeError. -
If rule["
source
"] is either of "fetch-event
" or "race-network-and-fetch-handler
", and serviceWorker’s set of event types to handle does not TypeError.
-
-
Let lifetimePromise be a new promise.
-
Add lifetime promise lifetimePromise to this.
Note:
event.addRoutes(rules)
extends the lifetime of the event by default as ifevent.waitUntil(promise)
is called. -
Let promise be a new promise.
-
Upon rejection of promise, resolve lifetimePromise with undefined.
Note: this step is for making lifetimePromise always fullfilled to avoid the install event failure.
-
Enqueue the following steps to [[service worker queue]]:
-
Let allRules be a copy of serviceWorker’s list of router rules.
-
For each rule of rules:
-
Append rule to allRules.
-
-
If running the Check Router Registration Limit with allRules returns false, reject promise with a
TypeError
. -
Set serviceWorker’s list of router rules to allRules.
-
Let serviceWorkerEventLoop be the event loop.
-
-
Resolve promise with undefined.
-
-
-
Return promise.
4.6. FetchEvent
[Exposed =ServiceWorker ]interface :
FetchEvent ExtendableEvent {(
constructor DOMString ,
type FetchEventInit ); [
eventInitDict Request request ;readonly attribute any >preloadResponse ;readonly attribute DOMString clientId ;readonly attribute DOMString resultingClientId ;readonly attribute DOMString replacesClientId ;readonly attribute undefined >handled ;Response >); };
r
dictionary :
FetchEventInit ExtendableEventInit {required Request ;
request any >;
preloadResponse DOMString = "";
clientId DOMString = "";
resultingClientId DOMString = "";
replacesClientId undefined >; };
handled
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
4.6.1. event.request
request
attribute must return the value it was initialized to.
4.6.2. event.preloadResponse
preloadResponse
attribute must return the value it was initialized to. When an a promise resolved with undefined.
4.6.3. event.clientId
clientId
attribute must return the value it was initialized to. When an event is created the attribute must be initialized to the empty string.
4.6.4. event.resultingClientId
resultingClientId
attribute must return the value it was initialized to. When an event is created the attribute must be initialized to the empty string.
4.6.5. event.replacesClientId
replacesClientId
attribute must return the value it was initialized to. When an event is created the attribute must be initialized to the empty string.
4.6.6. event.handled
handled
attribute must return the value it was initialized to. When an promise.
4.6.7. event.respondWith(r)
Note: Developers can set the argument r with either a network error is returned to Fetch.
respondWith(r)
method steps are:
-
Let event be this.
-
If event’s DOMException.
-
If event’s respond-with entered flag is set, DOMException.
-
Add lifetime promise r to event.
Note:
event.respondWith(r)
extends the lifetime of the event by default as ifevent.waitUntil(r)
is called. -
Set event’s stop immediate propagation flag.
-
Set event’s respond-with entered flag.
-
Set event’s wait to respond flag.
-
Let targetRealm be event’s relevant Realm.
-
Upon rejection of r:
-
Set event’s respond-with error flag.
-
Unset event’s wait to respond flag.
-
-
Upon fulfillment of r with response:
-
If response is not a
Response
object, then set the respond-with error flag.Note: If the respond-with error flag is set, a Fetch through Handle Fetch algorithm. (See the step 22.1.)
-
Else:
-
Let bytes be an empty byte sequence.
-
Let end-of-body be false.
-
Let done be false.
-
Let potentialResponse be a copy of response’s associated body.
-
If response’s body is non-null, run these substeps:
-
Let reader be the result of stream.
-
Let pullAlgorithm be an action that runs these steps:
-
Let readRequest be a new items:
- chunk steps, given chunk
-
-
Assert: chunk is a
Uint8Array
. -
Append the bytes represented by chunk to bytes.
-
Increment potentialResponse’s byte length.
-
Increment potentialResponse’s byte length.
-
Perform ! DetachArrayBuffer(chunk.[[ViewedArrayBuffer]]).
-
- close steps
-
-
Set end-of-body to true.
-
- error steps
-
Read a chunk from reader given readRequest.
-
-
Let cancelAlgorithm be an action that cancels reader.
-
Let highWaterMark be a non-negative, non-NaN number, chosen by the user agent.
-
Let sizeAlgorithm be an algorithm that accepts a chunk object and returns a non-negative, non-NaN, non-infinite number, chosen by the user agent.
-
Let newStream be a new
cancelAlgorithm cancelAlgorithm, the sizeAlgorithm sizeAlgorithm, in targetRealm.
-
Set potentialResponse’s stream is newStream.
-
Run these subsubsteps repeatedly in parallel while done is false:
-
If newStream is errored, then set done to true.
-
Otherwise, if bytes is empty and end-of-body is true, then close newStream and set done to true.
-
Otherwise, if bytes is not empty, run these subsubsubsteps:
-
Let chunk be a subsequence of bytes starting from the beginning of bytes.
-
Remove chunk from bytes.
-
Let buffer be an
ArrayBuffer
object created in targetRealm and containing chunk. -
Uint8Array object created in targetRealm and wrapping buffer to newStream.
-
-
Note: These substeps are meant to produce the observable equivalent of "piping" response’s stream into potentialResponse.
Note: The data written by the service worker in chunks are not guaranteed to read in identical chunks by the client that receives the data. That is, the client will read the same data that was written, but it may be chunked differently by the browser.
-
-
Set event’s potential response to potentialResponse.
-
-
Unset event’s wait to respond flag.
-
4.7. ExtendableMessageEvent
[Exposed =ServiceWorker ]interface :
ExtendableMessageEvent ExtendableEvent {(
constructor DOMString ,
type optional ExtendableMessageEventInit = {});
eventInitDict readonly attribute any data ;readonly attribute USVString origin ;readonly attribute DOMString lastEventId ; [MessagePort )?source ;readonly attribute MessagePort >ports ; };
dictionary :
ExtendableMessageEventInit ExtendableEventInit {any =
data null ;USVString = "";
origin DOMString = ""; (
lastEventId Client or ServiceWorker or MessagePort )?=
source null ;MessagePort >= []; };
ports
Service workers define the extendable message
event to allow extending the lifetime of the event. For the message
event, service workers use the ExtendableMessageEvent
interface which extends the ExtendableEvent
interface.
4.7.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.7.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.7.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.7.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.
4.7.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 the empty array. It represents the MessagePort
array being sent.
4.8. Events
The following events, called service worker events, are dispatched on ServiceWorkerGlobalScope
object:
5. Caches
To allow authors to fully manage their content caches for offline use, the origins, and they are completely isolated from the browser’s HTTP cache.
5.1. Constructs
A request response list is a response).
The relevant request response list is the instance that this represents.
A name to cache map is an value (a request response list).
Each storage key has an associated name to cache map.
The relevant name to cache map is the name to cache map associated with the environment settings object.
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 mixin WindowOrWorkerGlobalScope { [SameObject ]readonly attribute CacheStorage caches ; };
5.3.1. caches
caches
getter steps are to return this’s associated CacheStorage
object.
5.4. Cache
[Exposed =(Window ,Worker )]interface { [
Cache undefined )>match (RequestInfo ,
request optional CacheQueryOptions = {}); [
options Response >>matchAll (optional RequestInfo ,
request optional CacheQueryOptions = {}); [
options RequestInfo ); [
request sequence <RequestInfo >); [
requests RequestInfo ,
request Response ); [
response RequestInfo ,
request optional CacheQueryOptions = {}); [
options Request >>keys (optional RequestInfo ,
request optional CacheQueryOptions = {}); };
options
dictionary {
CacheQueryOptions boolean =
ignoreSearch false ;boolean =
ignoreMethod false ;boolean =
ignoreVary false ; };
A Cache
object represents a request response list. Multiple separate objects implementing the Cache
interface across documents and workers can all be associated with the same request response list simultaneously.
A cache batch operation is a struct that consists of:
-
A type ("
delete
" or "put
"). -
A request (a request).
-
A response (a response).
-
An options (a
CacheQueryOptions
).
5.4.1. match(request, options)
The match(request, options)
method steps are:
-
Let promise be a new promise.
-
Run these substeps in parallel:
-
Let p be the result of running the algorithm specified in
matchAll(request, options)
method with request and options. -
Wait until p settles.
-
If p rejects with an exception, then:
-
Reject promise with that exception.
-
-
Else if p resolves with an array, responses, then:
-
If responses is an empty array, then:
-
Resolve promise with undefined.
-
-
Else:
-
Resolve promise with the first element of responses.
-
-
-
-
Return promise.
5.4.2. matchAll(request, options)
The matchAll(request, options)
method steps are:
-
Let r be null.
-
If the optional argument request is not omitted, then:
-
If request is a
Request
object, then:-
Set r to request’s request.
-
If r’s a promise resolved with an empty array.
-
-
Else if request is a string, then:
-
Set r to the associated a promise rejected with that exception.
-
-
-
Let realm be relevant realm.
-
Let promise be a new promise.
-
Run these substeps in parallel:
-
Let responses be an empty list.
-
If the optional argument request is omitted, then:
-
For each requestResponse of the relevant request response list:
-
Add a copy of requestResponse’s response to responses.
-
-
-
Else:
-
Let requestResponses be the result of running Query Cache with r and options.
-
For each requestResponse of requestResponses:
-
Add a copy of requestResponse’s response to responses.
-
-
-
For each response of responses:
-
If response’s origin, promise’s internal response returns blocked, then reject promise with a
TypeError
and abort these steps.
-
-
DOM manipulation task source, to perform the following steps:
-
-
Return promise.
5.4.3. add(request)
The add(request)
method steps are:
-
Let requests be an array containing only request.
-
Let responseArrayPromise be the result of running the algorithm specified in
addAll(requests)
passing requests as the argument. -
Return the result of reacting to responseArrayPromise with a fulfillment handler that returns undefined.
5.4.4. addAll(requests)
The addAll(requests)
method steps are:
-
Let responsePromises be an empty list.
-
Let requestList be an empty list.
-
For each request whose type is
Request
in requests:-
Let r be request’s request.
-
If r’s a promise rejected with a
TypeError
.
-
-
Let fetchControllers be a fetch controllers.
-
For each request in requests:
-
Let r be the associated a promise rejected with that exception.
-
If r’s scheme is not one of "
http
" and "https
", then:-
abort fetchController.
-
Return a promise rejected with a
TypeError
.
-
-
If r’s service-workers mode to "
none
". -
Set r’s destination to "
subresource
". -
Add r to requestList.
-
Let responsePromise be a new promise.
-
Run the following substeps in parallel:
-
fetching r.
-
To processResponse for response, run these substeps:
-
To processResponseEndOfBody for response, run these substeps:
-
If response’s DOMException and abort these steps.
-
Resolve responsePromise with response.
Note: The cache commit is allowed when the response’s body is fully received.
-
-
-
Add responsePromise to responsePromises.
-
-
Let p be the result of getting a promise to wait for all of responsePromises.
-
Return the result of reacting to p with a fulfillment handler that, when called with argument responses, performs the following substeps:
-
Let operations be an empty list.
-
Let index be zero.
-
For each response in responses:
-
Let operation be a cache batch operation.
-
Set operation’s type to "
put
". -
Set operation’s request to requestList[index].
-
Set operation’s response to response.
-
Append operation to operations.
-
Increment index by one.
-
-
Let realm be relevant realm.
-
Let cacheJobPromise be a new promise.
-
Run the following substeps in parallel:
-
Let errorData be null.
-
Invoke Batch Cache Operations with operations. If this throws an exception, set errorData to the exception.
-
DOM manipulation task source, to perform the following substeps:
-
If errorData is null, resolve cacheJobPromise with undefined.
-
Else, reject cacheJobPromise with a exception with errorData, in realm.
-
-
-
Return cacheJobPromise.
-
5.4.5. put(request, response)
The put(request, response)
method steps are:
-
Let innerRequest be null.
-
If request is a
request.
-
Else:
-
Let requestObj be the result of invoking
a promise rejected with exception.
-
Set innerRequest to requestObj’s request.
-
-
If innerRequest’s a promise rejected with a
TypeError
. -
Let innerResponse be response’s response.
-
If innerResponse’s a promise rejected with a
TypeError
. -
If innerResponse’s named `
Vary
`, then:-
Let fieldValues be the field-values.
-
For each fieldValue in fieldValues:
-
If fieldValue matches "
*
", return a promise rejected with aTypeError
.
-
-
-
If innerResponse’s a promise rejected with a
TypeError
. -
Let clonedResponse be a clone of innerResponse.
-
Let bodyReadPromise be a promise resolved with undefined.
-
If innerResponse’s body is non-null, run these substeps:
-
Let stream be innerResponse’s stream.
-
Let reader be the result of getting a reader for stream.
-
Set bodyReadPromise to the result of reading all bytes from reader.
Note: This ensures that innerResponse’s locked, and we have a full buffered copy of the body in clonedResponse. An implementation could optimize by streaming directly to disk rather than memory.
-
-
Let operations be an empty list.
-
Let operation be a cache batch operation.
-
Set operation’s type to "
put
". -
Set operation’s request to innerRequest.
-
Set operation’s response to clonedResponse.
-
Append operation to operations.
-
Let realm be relevant realm.
-
Return the result of the fulfillment of bodyReadPromise:
-
Let cacheJobPromise be a new promise.
-
Return cacheJobPromise and run these steps in parallel:
-
Let errorData be null.
-
Invoke Batch Cache Operations with operations. If this throws an exception, set errorData to the exception.
-
DOM manipulation task source, to perform the following substeps:
-
If errorData is null, resolve cacheJobPromise with undefined.
-
Else, reject cacheJobPromise with a exception with errorData, in realm.
-
-
-
5.4.6. delete(request, options)
The delete(request, options)
method steps are:
-
Let r be null.
-
If request is a
Request
object, then:-
Set r to request’s request.
-
If r’s a promise resolved with false.
-
-
Else if request is a string, then:
-
Set r to the associated a promise rejected with that exception.
-
-
Let operations be an empty list.
-
Let operation be a cache batch operation.
-
Set operation’s type to "
delete
". -
Set operation’s request to r.
-
Set operation’s options to options.
-
Append operation to operations.
-
Let realm be relevant realm.
-
Let cacheJobPromise be a new promise.
-
Run the following substeps in parallel:
-
Let errorData be null.
-
Let requestResponses be the result of running Batch Cache Operations with operations. If this throws an exception, set errorData to the exception.
-
DOM manipulation task source, to perform the following substeps:
-
If errorData is null, then:
-
If requestResponses is not empty, resolve cacheJobPromise with true.
-
Else, resolve cacheJobPromise with false.
-
-
Else, reject cacheJobPromise with a exception with errorData, in realm.
-
-
-
Return cacheJobPromise.
5.4.7. keys(request, options)
The keys(request, options)
method steps are:
-
Let r be null.
-
If the optional argument request is not omitted, then:
-
If request is a
Request
object, then:-
Set r to request’s request.
-
If r’s a promise resolved with an empty array.
-
-
Else if request is a string, then:
-
Set r to the associated a promise rejected with that exception.
-
-
-
Let realm be relevant realm.
-
Let promise be a new promise.
-
Run these substeps in parallel:
-
Let requests be an empty list.
-
If the optional argument request is omitted, then:
-
For each requestResponse of the relevant request response list:
-
Add requestResponse’s request to requests.
-
-
-
Else:
-
Let requestResponses be the result of running Query Cache with r and options.
-
For each requestResponse of requestResponses:
-
Add requestResponse’s request to requests.
-
-
-
DOM manipulation task source, to perform the following steps:
-
-
Return promise.
5.5. CacheStorage
[Exposed =(Window ,Worker )]interface { [
CacheStorage undefined )>match (RequestInfo ,
request optional MultiCacheQueryOptions = {}); [
options DOMString ); [
cacheName DOMString ); [
cacheName DOMString ); [
cacheName DOMString >>keys (); };dictionary :
MultiCacheQueryOptions CacheQueryOptions {DOMString ; };
cacheName
Note: 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 WorkerGlobalScope
object is created and associate it with that global object.
A CacheStorage
object represents a name to cache map of its associated global object’s origin. Multiple separate objects implementing the CacheStorage
interface across documents and workers can all be associated with the same name to cache map simultaneously.
5.5.1. match(request, options)
The match(request, options)
method steps are:
-
If options["
cacheName
"] exists, then:-
Return in parallel:
-
For each cacheName → cache of the relevant name to cache map:
-
If options["
cacheName
"] matches cacheName, then:-
Resolve promise with the result of running the algorithm specified in
match(request, options)
method ofCache
interface with request and options (providing cache as thisArgument to the\[[Call]]
internal method ofmatch(request, options)
.) -
Abort these steps.
-
-
-
Resolve promise with undefined.
-
-
-
Else:
-
Let promise be a promise resolved with undefined.
-
For each cacheName → cache of the relevant name to cache map:
-
Set promise to the result of reacting to itself with a fulfillment handler that, when called with argument response, performs the following substeps:
-
If response is not undefined, return response.
-
Return the result of running the algorithm specified in
match(request, options)
method ofCache
interface with request and options as the arguments (providing cache as thisArgument to the\[[Call]]
internal method ofmatch(request, options)
.)
-
-
-
Return promise.
-
5.5.2. has(cacheName)
The has(cacheName)
method steps are:
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
For each key → value of the relevant name to cache map:
-
If cacheName matches key, resolve promise with true and abort these steps.
-
-
Resolve promise with false.
-
-
Return promise.
5.5.3. open(cacheName)
The open(cacheName)
method steps are:
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
For each key → value of the relevant name to cache map:
-
If cacheName matches key, then:
-
Resolve promise with a new
Cache
object that represents value. -
Abort these steps.
-
-
-
Let cache be a new request response list.
-
DOMException and abort these steps.
-
Resolve promise with a new
Cache
object that represents cache.
-
-
Return promise.
5.5.4. delete(cacheName)
The delete(cacheName)
method steps are:
-
Let promise be the result of running the algorithm specified in
has(cacheName)
method with cacheName. -
Return the result of reacting to promise with a fulfillment handler that, when called with argument cacheExists, performs the following substeps:
-
If cacheExists is false, then:
-
Return false.
-
-
Let cacheJobPromise be a new promise.
-
Run the following substeps in parallel:
-
Remove the relevant name to cache map[cacheName].
-
Resolve cacheJobPromise with true.
Note: After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional.
-
-
Return cacheJobPromise.
-
5.5.5. keys()
The keys()
method steps are:
-
Let promise be a new promise.
-
Run the following substeps in parallel:
-
Let cacheKeys be the result of getting the keys of the relevant name to cache map.
Note: The ordered set are in the order that their corresponding entry was added to the name to cache map.
-
Resolve promise with cacheKeys.
-
-
Return promise.
6. Security Considerations
6.1. Secure Context
Service workers must execute in 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.
Note: This effectively means that service workers and their service worker clients need to be hosted over HTTPS. A user agent can allow localhost
(see risks associated with insecure contexts.
6.2. Content Security Policy
Whenever a user agent invokes the 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 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)
method is called on a ServiceWorkerGlobalScope
object, the user agent must request request:
-
Let serviceWorker be request’s global object’s service worker.
-
Let map be serviceWorker’s script resource map.
-
Let url be request’s url.
-
If serviceWorker’s state is not "
parsed
" or "installing
":-
Return map[url] if it network error otherwise.
-
-
If map[url] exists:
-
Append url to serviceWorker’s set of used scripts.
-
Return map[url].
-
-
Let registration be serviceWorker’s containing service worker registration.
-
Set request’s service-workers mode to "
none
". -
Set request’s cache mode to "
no-cache
" if any of the following are true:-
registration’s update via cache mode is "
none
". -
The current global object’s force bypass cache for import scripts flag is set.
-
registration is stale.
-
-
Let response be the result of fetching request.
-
If response’s cache state is not "
local
", set registration’s last update check time to the current time. -
If response’s network error.
-
Set map[url] to response.
-
Append url to serviceWorker’s set of used scripts.
-
Set serviceWorker’s classic scripts imported flag.
-
Return response.
6.4. Cross-Origin Resources and CORS
This section is non-normative.
Applications tend to cache items that come from a CDN or other 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 Response objects whose corresponding 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. Path restriction
This section is non-normative.
In addition to the origin restriction, service workers are restricted by the path of the service worker script. For example, a service worker script at https://www.example.com/~bob/sw.js
can be registered for the scope url https://www.example.com/~bob/
but not for the scope https://www.example.com/
or https://www.example.com/~alice/
. This provides some protection for sites that host multiple-user content in separated directories on the same origin. However, the path restriction is not considered a hard security boundary, as only origins are. Sites are encouraged to use different origins to securely isolate segments of the site if appropriate.
Servers can remove the path restriction by setting a Service-Worker-Allowed header on the service worker script.
6.6. Service worker script request
This section is non-normative.
To further defend against malicious registration of a service worker on a site, this specification requires that:
-
The Service-Worker header is present on service worker script requests, and
-
Service worker scripts are served with a JavaScript MIME type.
6.7. 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
<embed>
and<object>
requests immediately fallback to the network without dispatchingfetch
event. -
Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with service workers.
6.8. Privacy
Service workers introduce new persistent storage features including registration map (for service worker registrations and their service workers), request response list 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. Extensibility
Service Workers specification is extensible from other specifications.
7.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 namespacereadonly attribute APISpaceType APISpace ; / e.g. define a methodPromise <T >methodName (/* list of arguments */); };
7.2. Define Functional Event
Specifications may define a functional event by extending ExtendableEvent
interface:
/ e.g. define FunctionalEvent interfaceinterface FunctionalEvent :ExtendableEvent { / add a functional event’s own attributes and methods };
7.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 ; };
7.4. Firing Functional Events
To request a functional event dispatch to the active worker of a service worker registration, specifications should invoke Fire Functional Event.
Appendix A: Algorithms
The following definitions are the user agent’s internal data structures used throughout the specification.
A registration map is an serialized scope urls) and the values are service worker registrations.
A job is an abstraction of one of register, update, and unregister request for a service worker registration.
A job has a storage key (a storage key).
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 an update via cache mode, which is "imports
", "all
", or "none
".
A job has a client (a service worker client). It is initially null.
A job has a referrer (a URL or null).
A job has a job promise (a promise). It is initially null.
A job has a containing job queue (a job queue or null). It is initially null.
A job has a list of equivalent jobs (a list of jobs). 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:
-
For register and update jobs, their scope url, script url, worker type, and update via cache mode are the same.
A job queue is a thread safe items. A job queue is initially empty.
A scope to job queue map is an serialized, and the values are job queues.
A bad import script response is a response for which any of the following conditions are met:
-
response’s type is "
error
" -
response’s ok status
-
The result of JavaScript MIME type
Note: Keep this definition in sync with fetch a classic worker-imported script.
Create Job
- Input
-
jobType, a job type
storage key, a storage key
scopeURL, a URL
scriptURL, a URL
promise, a promise
client, a service worker client
- Output
-
job, a job
-
Let job be a new job.
-
Set job’s job type to jobType.
-
Set job’s storage key to storage key.
-
Set job’s scope url to scopeURL.
-
Set job’s script url to scriptURL.
-
Set job’s job promise to promise.
-
Set job’s client to client.
-
If client is not null, set job’s referrer to client’s creation URL.
-
Return job.
Schedule Job
- Input
-
job, a job
- Output
-
none
-
Let jobQueue be null.
-
Let jobScope be job’s scope url, serialized.
-
If scope to job queue map[jobScope] does not set scope to job queue map[jobScope] to a new job queue.
-
Set jobQueue to scope to job queue map[jobScope].
-
If jobQueue is empty, then:
-
Set job’s containing job queue to jobQueue, and enqueue job to jobQueue.
-
Invoke Run Job with jobQueue.
-
-
Else:
-
Let lastJob be the element at the back of jobQueue.
-
If job is equivalent to lastJob and lastJob’s job promise has not settled, append job to lastJob’s list of equivalent jobs.
-
Else, set job’s containing job queue to jobQueue, and enqueue job to jobQueue.
-
Run Job
- Input
-
jobQueue, a job queue
- Output
-
none
-
Assert: jobQueue is not empty.
-
Queue a task to run these steps:
-
Let job be the first item in jobQueue.
-
If job’s job type is register, run Register with job in parallel.
-
Else if job’s job type is update, run Update with job in parallel.
Note: For a register job and an update job, the user agent delays queuing a task for running the job until after a
DOMContentLoaded
event has been dispatched to the document that initiated the job. -
Else if job’s job type is unregister, run Unregister with job in parallel.
-
Finish Job
- Input
-
job, a job
- Output
-
none
-
Let jobQueue be job’s containing job queue.
-
Assert: the first item in jobQueue is job.
-
Dequeue from jobQueue.
-
If jobQueue is not empty, invoke Run Job with jobQueue.
Resolve Job Promise
- Input
-
job, a job
value, any
- Output
-
none
-
If job’s client is not null, DOM manipulation task source, to run the following substeps:
-
Let convertedValue be null.
-
If job’s job type is either register or update, set convertedValue to the result of getting the service worker registration object that represents value in job’s client.
-
Resolve job’s job promise with convertedValue.
-
-
For each equivalentJob in job’s list of equivalent jobs:
-
If equivalentJob’s client is null, continue to the next iteration of the loop.
-
DOM manipulation task source, to run the following substeps:
-
Let convertedValue be null.
-
If equivalentJob’s job type is either register or update, set convertedValue to the result of getting the service worker registration object that represents value in equivalentJob’s client.
-
Else, set convertedValue to value, in equivalentJob’s client’s Realm.
-
Resolve equivalentJob’s job promise with convertedValue.
-
-
Reject Job Promise
- Input
-
job, a job
errorData, the information necessary to create an exception
- Output
-
none
Start Register
- Input
-
scopeURL, a URL or failure or null
scriptURL, a URL or failure
promise, a promise
client, a service worker client
referrer, a URL
workerType, a worker type
updateViaCache, an update via cache mode
- Output
-
none
-
If scriptURL is failure, reject promise with a
TypeError
and abort these steps. -
Set scriptURL’s fragment to null.
Note: The user agent does not store the fragment does not have an effect on identifying service workers.
-
If scriptURL’s scheme is not one of "
http
" and "https
", reject promise with aTypeError
and abort these steps. -
If any of the strings in scriptURL’s ASCII case-insensitive "
%5c
", reject promise with aTypeError
and abort these steps. -
If scopeURL is null, set scopeURL to the result of parsing the string "
./
" with scriptURL.Note: The scope url for the registration is set to the location of the service worker script by default.
-
If scopeURL is failure, reject promise with a
TypeError
and abort these steps. -
Set scopeURL’s fragment to null.
Note: The user agent does not store the fragment does not have an effect on identifying service worker registrations.
-
If scopeURL’s scheme is not one of "
http
" and "https
", reject promise with aTypeError
and abort these steps. -
If any of the strings in scopeURL’s ASCII case-insensitive "
%5c
", reject promise with aTypeError
and abort these steps. -
Let storage key be the result of running obtain a storage key given client.
-
Let job be the result of running Create Job with register, storage key, scopeURL, scriptURL, promise, and client.
-
Set job’s worker type to workerType.
-
Set job’s update via cache mode to updateViaCache.
-
Set job’s referrer to referrer.
-
Invoke Schedule Job with job.
Register
- Input
-
job, a job
- Output
-
none
-
If the result of running origin of job’s script url as the argument is
Not Trusted
, then:-
Invoke Reject Job Promise with job and "
DOMException
. -
Invoke Finish Job with job and abort these steps.
-
-
If job’s script url’s same origin, then:
-
Invoke Reject Job Promise with job and "
DOMException
. -
Invoke Finish Job with job and abort these steps.
-
-
If job’s scope url’s same origin, then:
-
Invoke Reject Job Promise with job and "
DOMException
. -
Invoke Finish Job with job and abort these steps.
-
-
Let registration be the result of running Get Registration given job’s storage key and job’s scope url.
-
If registration is not null, then:
-
Let newestWorker be the result of running the Get Newest Worker algorithm passing registration as the argument.
-
If newestWorker is not null, job’s script url equals newestWorker’s script url, job’s worker type equals newestWorker’s type, and job’s update via cache mode’s value equals registration’s update via cache mode, then:
-
Invoke Resolve Job Promise with job and registration.
-
Invoke Finish Job with job and abort these steps.
-
-
-
Else:
-
Invoke Set Registration algorithm with job’s storage key, job’s scope url, and job’s update via cache mode.
-
-
Invoke Update algorithm passing job as the argument.
Update
- Input
-
job, a job
- Output
-
none
-
Let registration be the result of running Get Registration given job’s storage key and job’s scope url.
-
If registration is null, then:
-
Invoke Reject Job Promise with job and
TypeError
. -
Invoke Finish Job with job and abort these steps.
-
-
Let newestWorker be the result of running Get Newest Worker algorithm passing registration as the argument.
-
If job’s job type is update, and newestWorker is not null and its script url does not equal job’s script url, then:
-
Invoke Reject Job Promise with job and
TypeError
. -
Invoke Finish Job with job and abort these steps.
-
-
Let hasUpdatedResources be false.
-
Switching on job’s worker type, run these substeps with the following options:
- "
classic
" -
environment settings object for this service worker.
- "
module
" -
environment settings object for this service worker.
Using the to-be-created web workers require an environment settings object of the execution environment, but service workers fetch a script separately in the Update algorithm before the script later runs multiple times through the Run Service Worker algorithm.
The fetch a module worker script graph algorithm in HTML take job’s client as an argument. job’s client is null when passed from the Soft Update algorithm.
To perform the fetch hook given request, run the following steps:
-
Append `
Service-Worker
`/`script
` to request’s header list.Note: See the definition of the Service-Worker header in Appendix B: Extended HTTP headers.
-
Set request’s cache mode to "
no-cache
" if any of the following are true:-
registration’s update via cache mode is not "
all
". -
job’s force bypass cache flag is set.
-
newestWorker is not null and registration is stale.
Note: Even if the cache mode is not set to "
no-cache
", the user agent obeys Cache-Control header’s max-age value in the network layer to determine if it should bypass the browser cache. -
-
Set request’s service-workers mode to "
none
". -
If the fetching request.
-
Set request’s redirect mode to "
error
". -
response response.
-
JavaScript MIME type, then:
-
Invoke Reject Job Promise with job and "
DOMException
. -
Asynchronously complete these steps with a network error.
-
-
Let serviceWorkerAllowed be the result of header list.
Note: See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers.
-
Set policyContainer to the result of creating a policy container from a fetch response given response.
-
If serviceWorkerAllowed is failure, then:
-
Asynchronously complete these steps with a network error.
-
-
Let scopeURL be registration’s scope url.
-
Let maxScopeString be null.
-
If serviceWorkerAllowed is null, then:
-
Let resolvedScope be the result of base URL.
-
Set maxScopeString to "
/
", followed by the strings in resolvedScope’s path (including empty strings), separated from each other by "/
".Note: The final item in resolvedScope’s path will always be an empty string, so maxScopeString will have a trailing "
/
".
-
-
Else:
-
Let scopeString be "
/
", followed by the strings in scopeURL’s path (including empty strings), separated from each other by "/
". -
If maxScopeString is null or scopeString does not start with maxScopeString, then:
-
Invoke Reject Job Promise with job and "
DOMException
. -
Asynchronously complete these steps with a network error.
-
-
Let url be request’s url.
-
Set updatedResourceMap[url] to response.
-
If response’s cache state is not "
local
", set registration’s last update check time to the current time. -
Set hasUpdatedResources to true if any of the following are true:
-
newestWorker is null.
-
newestWorker’s script url is not url or newestWorker’s type is not job’s worker type.
-
newestWorker’s script resource map[url]'s body.
-
-
If hasUpdatedResources is false and newestWorker’s classic scripts imported flag is set, then:
Note: The following checks to see if an imported script has been updated, since the main script has not changed.
-
For each importUrl → storedResponse of newestWorker’s script resource map:
-
If importUrl is url, then continue.
-
Let importRequest be a new destination is "
script
", use-URL-credentials flag is set. -
Set importRequest’s cache mode to "
no-cache
" if any of the following are true:-
registration’s update via cache mode is "
none
". -
job’s force bypass cache flag is set.
-
registration is stale.
-
-
Let fetchedResponse be the result of fetching importRequest.
-
Set updatedResourceMap[importRequest’s url] to fetchedResponse.
-
Set fetchedResponse to fetchedResponse’s unsafe response.
-
If fetchedResponse’s cache state is not "
local
", set registration’s last update check time to the current time. -
If fetchedResponse is a bad import script response, continue.
Note: Bad responses for importScripts() are ignored for the purpose of the byte-to-byte check. Only good responses for the incumbent worker and good responses for the potential update worker are considered. See issue #1374 for some rationale.
-
If fetchedResponse’s body, set hasUpdatedResources to true.
Note: The control does not break the loop in this step to continue with all the imported scripts to populate the cache.
-
-
-
Asynchronously complete these steps with response.
When the algorithm asynchronously completes, continue the rest of these steps, with script being the asynchronous completion value.
- "
-
If script is null or Is Async Module with script’s base URL, and « » is true, then:
-
Invoke Reject Job Promise with job and
TypeError
.Note: This will do nothing if Reject Job Promise was previously invoked with "
DOMException
. -
If newestWorker is null, then serialized scopeURL)].
-
Invoke Finish Job with job and abort these steps.
-
-
If hasUpdatedResources is false, then:
-
Set registration’s update via cache mode to job’s update via cache mode.
-
Invoke Resolve Job Promise with job and registration.
-
Invoke Finish Job with job and abort these steps.
-
-
Let worker be a new service worker.
-
Set worker’s script url to job’s script url, worker’s script resource to script, worker’s type to job’s worker type, and worker’s script resource map to updatedResourceMap.
-
Append url to worker’s set of used scripts.
-
Set worker’s script resource’s policy container to policyContainer.
-
Let forceBypassCache be true if job’s force bypass cache flag is set, and false otherwise.
-
Let runResult be the result of running the Run Service Worker algorithm with worker and forceBypassCache.
-
If runResult is failure or an abrupt completion, then:
-
Invoke Reject Job Promise with job and
TypeError
. -
If newestWorker is null, then serialized scopeURL)].
-
Invoke Finish Job with job.
-
-
Else, invoke Install algorithm 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
forceBypassCache, an optional boolean, false by default
Note: Implementers may use forceBypassCache 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
-
Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
-
If newestWorker is null, abort these steps.
-
Let job be the result of running Create Job with update, registration’s storage key, registration’s scope url, newestWorker’s script url, null, and null.
-
Set job’s worker type to newestWorker’s type.
-
Set job’s force bypass cache flag if forceBypassCache is true.
-
Invoke Schedule Job with job.
Install
- Input
-
job, a job
worker, a service worker
registration, a service worker registration
- Output
-
none
-
Let installFailed be false.
-
Let newestWorker be the result of running Get Newest Worker algorithm passing registration as its argument.
-
Set registration’s update via cache mode to job’s update via cache mode.
-
Run the Update Registration State algorithm passing registration, "
installing
" and worker as the arguments. -
Run the Update Worker State algorithm passing registration’s installing worker and "
installing
" as the arguments. -
Assert: job’s job promise is not null.
-
Invoke Resolve Job Promise with job and registration.
-
Let settingsObjects be all origin.
-
For each settingsObject of settingsObjects, DOM manipulation task source to run the following steps:
-
Let registrationObjects be every
ServiceWorkerRegistration
object in settingsObject’s realm, whose service worker registration is registration. -
For each registrationObject of registrationObjects, fire an event on registrationObject named
updatefound
.
-
-
Let installingWorker be registration’s installing worker.
-
If the result of running the Should Skip Event algorithm with installingWorker and "install" is false, then:
-
Let forceBypassCache be true if job’s force bypass cache flag is set, and false otherwise.
-
If the result of running the Run Service Worker algorithm with installingWorker and forceBypassCache is failure, then:
-
Set installFailed to true.
-
-
Else:
-
DOM manipulation task source to run the following steps:
-
Let e be the result of creating an event with
InstallEvent
. -
Dispatch e at installingWorker’s global object.
-
WaitForAsynchronousExtensions: Run the following substeps in parallel:
-
Wait until e is not active.
-
If e’s timed out flag is set, set installFailed to true.
-
Let p be the result of getting a promise to wait for all of e’s extend lifetime promises.
-
Upon rejection of p, set installFailed to true.
-
If task is discarded, set installFailed to true.
-
-
Wait for task to have executed or been discarded.
-
Wait for the step labeled WaitForAsynchronousExtensions to complete.
-
-
-
If installFailed is true, then:
-
Run the Update Worker State algorithm passing registration’s installing worker and "
redundant
" as the arguments. -
Run the Update Registration State algorithm passing registration, "
installing
" and null as the arguments. -
If newestWorker is null, then serialized registration’s scope url)].
-
Invoke Finish Job with job and abort these steps.
-
-
Let map be registration’s installing worker’s script resource map.
-
Let usedSet be registration’s installing worker’s set of used scripts.
-
For each url of map:
-
If usedSet does not remove map[url].
-
-
If registration’s waiting worker is not null, then:
-
Terminate registration’s waiting worker.
-
Run the Update Worker State algorithm passing registration’s waiting worker and "
redundant
" as the arguments.
-
-
Run the Update Registration State algorithm passing registration, "
waiting
" and registration’s installing worker as the arguments. -
Run the Update Registration State algorithm passing registration, "
installing
" and null as the arguments. -
Run the Update Worker State algorithm passing registration’s waiting worker and "
installed
" as the arguments. -
Invoke Finish Job with job.
-
Wait for all the queued by Update Worker State invoked in this algorithm to have executed.
-
Invoke Try Activate with registration.
Note: If Try Activate does not trigger Activate here, Activate is tried again when the last client controlled by the existing active worker is unloaded,
skipWaiting()
is asynchronously called, or the extend lifetime promises for the existing active worker settle.
Activate
- Input
-
registration, a service worker registration
- Output
-
None
-
If registration’s waiting worker is null, abort these steps.
-
If registration’s active worker is not null, then:
-
Terminate registration’s active worker.
-
Run the Update Worker State algorithm passing registration’s active worker and "
redundant
" as the arguments.
-
-
Run the Update Registration State algorithm passing registration, "
active
" and registration’s waiting worker as the arguments. -
Run the Update Registration State algorithm passing registration, "
waiting
" and null as the arguments. -
Run the Update Worker State algorithm passing registration’s active worker and "
activating
" as the arguments.Note: 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.
Note: Make sure to design activation handlers to do non-essential work (like cleanup). This is because activation handlers may not all run to completion, especially in the case of browser termination during activation. A Service Worker should be designed to function properly, even if the activation handlers do not all complete successfully.
-
Let matchedClients be a creation URL matches registration’s storage key and registration’s scope url.
-
DOM manipulation task source, to run the following substeps:
-
Let readyPromise be client’s global object’s
ServiceWorkerContainer
object’s ready promise. -
If readyPromise is null, then continue.
-
If readyPromise is pending, resolve readyPromise with the the result of getting the service worker registration object that represents registration in readyPromise’s relevant settings object.
-
-
For each service worker client client who is using registration:
-
Set client’s active worker to registration’s active worker.
-
Invoke Notify Controller Change algorithm with client as the argument.
-
-
Let activeWorker be registration’s active worker.
-
If the result of running the Should Skip Event algorithm with activeWorker and "activate" is false, then:
-
If the result of running the Run Service Worker algorithm with activeWorker is not failure, then:
-
DOM manipulation task source to run the following steps:
-
Let e be the result of creating an event with
ExtendableEvent
. -
Dispatch e at activeWorker’s global object.
-
WaitForAsynchronousExtensions: Wait, in parallel, until e is not active.
-
-
Wait for task to have executed or been discarded.
-
Wait for the step labeled WaitForAsynchronousExtensions to complete.
-
-
-
Run the Update Worker State algorithm passing registration’s active worker and "
activated
" as the arguments.
Try Activate
- Input
-
registration, a service worker registration
- Output
-
None
-
If registration’s waiting worker is null, return.
-
If registration’s active worker is not null and registration’s active worker’s state is "
activating
", return.Note: If the existing active worker is still in activating state, the activation of the waiting worker is delayed.
-
Invoke Activate with registration if either of the following is true:
-
registration’s active worker is null.
-
The result of running Service Worker Has No Pending Events with registration’s active worker is true, and no service worker client is using registration or registration’s waiting worker’s skip waiting flag is set.
-
Setup ServiceWorkerGlobalScope
- Input
-
serviceWorker, a service worker
- Output
-
a
ServiceWorkerGlobalScope
object or null
Note: This algorithm returns a ServiceWorkerGlobalScope
usable for a CSP check, or null. If serviceWorker has an active ServiceWorkerGlobalScope
, then it is returned. Otherwise, the object will be newly created.
In specifications, such security checks require creating a ServiceWorkerGlobalScope
, a agent. In implementations, the amount of work required might be much less. Therefore, implementations could do less work in their equivalent of this algorithm, and more work in Run Service Worker, as long as the results are observably equivalent. (And in particular, as long as all security checks have the same result.)
-
Let unsafeCreationTime be the unsafe shared current time.
-
If serviceWorker is running, then return serviceWorker’s global object.
-
If serviceWorker’s state is "
redundant
", then return null. -
If serviceWorker’s global object is not null, then return serviceWorker’s global object.
-
Assert: serviceWorker’s start status is null.
-
Let setupFailed be false.
-
Let globalObject be null.
-
Let agent be the result of obtaining a service worker agent, and run the following steps in that context:
-
Let realmExecutionContext be the result of creating a new realm given agent and the following customizations:
-
For the global object, create a new
ServiceWorkerGlobalScope
object. Let workerGlobalScope be the created object.
-
-
Let settingsObject be a new environment settings object whose algorithms are defined as follows:
- The realm execution context
-
Return realmExecutionContext.
- The module map
-
Return workerGlobalScope’s module map.
- The API base URL
-
Return serviceWorker’s script url.
- The origin
-
Return its registering service worker client’s origin.
- The policy container
-
Return workerGlobalScope’s policy container.
- The time origin
-
Return the result of cross-origin isolated capability.
-
Set settingsObject’s top-level origin to an active service worker to null.
-
Set workerGlobalScope’s url to serviceWorker’s script url.
-
Set workerGlobalScope’s policy container to serviceWorker’s script resource’s policy container.
-
Create a new
WorkerLocation
object and associate it with workerGlobalScope. -
If the run CSP initialization for a global object algorithm returns "
Blocked
" when executed upon workerGlobalScope, set setupFailed to true and abort these steps. -
Set globalObject to workerGlobalScope.
-
-
Wait for globalObject is not null, or for setupFailed to be true.
-
If setupFailed is true, then return null.
-
Return globalObject.
Run Service Worker
- Input
-
serviceWorker, a service worker
forceBypassCache, an optional boolean, false by default
- Output
-
a Completion or failure
Note: This algorithm blocks until the service worker is running or fails to start.
-
If serviceWorker is running, then return serviceWorker’s start status.
-
If serviceWorker’s state is "
redundant
", then return failure. -
Assert: serviceWorker’s start status is null.
-
Let script be serviceWorker’s script resource.
-
Assert: script is not null.
-
Let startFailed be false.
-
Let workerGlobalScope be serviceWorker’s global object.
-
If workerGlobalScope is null:
-
Set workerGlobalScope to be the result of running the Setup ServiceWorkerGlobalScope algorithm with serviceWorker.
-
If workerGlobalScope is null, then return failure.
-
Set serviceWorker’s global object to workerGlobalScope.
-
-
Obtain agent for workerGlobalScope’s realm execution context, and run the following steps in that context:
-
Set workerGlobalScope’s force bypass cache for import scripts flag if forceBypassCache is true.
-
If serviceWorker is an active worker, and there are any task queues in the same order using their original task sources.
-
Let evaluationStatus be null.
-
If script is a classic script, then:
-
Set evaluationStatus to the result of running the classic script script.
-
If evaluationStatus.[[Value]] is empty, this means the script was not evaluated. Set startFailed to true and abort these steps.
-
-
Otherwise, if script is a module script, then:
-
Let evaluationPromise be the result of running the module script script, with report errors set to false.
-
Assert: evaluationPromise.[[PromiseState]] is not "pending".
-
If evaluationPromise.[[PromiseState]] is "rejected":
-
Set evaluationStatus to ThrowCompletion(evaluationPromise.[[PromiseResult]]).
-
-
Otherwise:
-
Set evaluationStatus to NormalCompletion(undefined).
-
-
-
If the script was aborted by the Terminate Service Worker algorithm, set startFailed to true and abort these steps.
-
Set serviceWorker’s start status to evaluationStatus.
-
If script’s has ever been evaluated flag is unset, then:
-
For each eventType of settingsObject’s event listeners' event types:
-
Append eventType to workerGlobalScope’s associated service worker’s set of event types to handle.
Note: 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 remains an empty set.
-
-
Set script’s has ever been evaluated flag.
-
Unset the serviceWorker’s all fetch listeners are empty flag.
-
The user agent may, if the All Fetch Listeners Are Empty algorithm with workerGlobalScope returns true, set serviceWorker’s all fetch listeners are empty flag.
-
-
Run the responsible event loop specified by settingsObject until it is destroyed.
-
-
Wait for serviceWorker to be running, or for startFailed to be true.
-
If startFailed is true, then return failure.
-
Return serviceWorker’s start status.
All Fetch Listeners Are Empty
- Input
-
workerGlobalScope, a global object.
- Output
-
a boolean
-
If workerGlobalScope’s set of event types to handle does not contain
fetch
, then return true. -
Let eventHandler be workerGlobalScope’s event handler map["onfetch"]'s value.
-
Let eventListenerCallbacks be the result of calling legacy-obtain service worker fetch event listener callbacks given workerGlobalScope.
-
For each eventListenerCallback of eventListenerCallbacks:
-
Let callback be null.
-
If eventHandler is not null and eventListenerCallback equals eventHandler’s value.
-
Otherwise, set callback to the result of converting to an ECMAScript value eventListenerCallback.
-
If IsCallable(callback) is false, then return false.
Note: handleEvent(event) getters, which could modify the event listeners during this check.
-
If callback’s declaration exist), then return false.
Note: This detects "
fetch
" listeners like() => {}
. Some sites have a fetch event listener with empty body to make them recognized by Chromium as a progressive web application (PWA). -
-
Return true.
Note: User agents are encouraged to show a warning indicating that empty "fetch
" listeners are unnecessary, and may have a negative performance impact.
Terminate Service Worker
- Input
-
serviceWorker, a service worker
- Output
-
None
-
Run the following steps in parallel with serviceWorker’s main loop:
-
Let serviceWorkerGlobalScope be serviceWorker’s global object.
-
Set serviceWorkerGlobalScope’s closing flag to true.
-
items from serviceWorker’s set of extended events.
-
If there are any task queues, tasks whose task queues without processing them.
Note: 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.
-
Abort the script currently running in serviceWorker.
-
Set serviceWorker’s start status to null.
-
Handle Fetch
The Handle Fetch algorithm is the entry point for the fetch handling handed to the service worker context.
- Input
-
request, a request
fetchController, a fetch controller
useHighResPerformanceTimers, a boolean
- Output
-
a response
-
Let registration be null.
-
Let client be request’s client.
-
Let reservedClient be request’s reserved client.
-
Let preloadResponse be a new promise.
-
Let workerRealm be null.
-
Let timingInfo be a new service worker timing info.
-
Assert: request’s destination is not "
serviceworker
". -
If request’s destination is either "
embed
" or "object
", then:-
Return null.
-
-
Else if request is a non-subresource request, then:
-
If reservedClient is not null and is an environment settings object, then:
-
If reservedClient is not a secure context, return null.
-
-
Else:
-
If request’s potentially trustworthy URL, return null.
-
-
If request is a navigation triggering it was initiated with a shift+reload or equivalent, return null.
-
Assert reservedClient is not null.
-
Let storage key be the result of running obtain a storage key given reservedClient.
-
Set registration to the result of running Match Service Worker Registration given storage key and request’s url.
-
If registration is null or registration’s active worker is null, return null.
-
If request’s active service worker to registration’s active worker.
Note: From this point, the service worker client starts to use its active service worker’s containing service worker registration.
-
-
Else if request is a subresource request, then:
-
If client’s active service worker’s containing service worker registration.
-
Else, return null.
-
-
Let activeWorker be registration’s active worker.
-
Let shouldSoftUpdate be true if any of the following are true, and false otherwise:
-
request is a non-subresource request.
-
request is a subresource request and registration is stale.
-
-
If activeWorker’s list of router rules is not empty:
-
Let source be the result of running the Get Router Source algorithm with registration’s active worker and request.
-
If source is
"network"
:-
If shouldSoftUpdate is true, then in parallel run the Soft Update algorithm with registration.
-
Return null.
-
-
Else if source is
"cache"
, or source["cacheName
"] exists, then:-
If shouldSoftUpdate is true, then in parallel run the Soft Update algorithm with registration.
-
For each cacheName → cache of the registration’s storage key’s name to cache map.
-
Let requestResponses be the result of running Query Cache with request, a new
CacheQueryOptions
, and cache. -
If requestResponses is an empty list, return null.
-
Else:
-
Let requestResponse be the first element of requestResponses.
-
Let response be requestResponse’s response.
-
Let globalObject be activeWorker’s global object.
-
If globalObject is null:
-
Set globalObject to the result of running Setup ServiceWorkerGlobalScope with activeWorker.
-
-
If globalObject is null, return null.
Note: This only creates a ServiceWorkerGlobalScope because CORS checks require that. It is not expected that implementations will actually create a ServiceWorkerGlobalScope here.
-
If response’s internal response returns blocked, then return null.
-
Return response.
-
-
Return null.
-
-
Else if source is
"race-network-and-fetch-handler"
, and request’s method is `GET
` then:-
If shouldSoftUpdate is true, then in parallel run the Soft Update algorithm with registration.
-
Let queue be an empty response.
-
Let raceFetchController be null.
-
Let raceResponse be a race response whose value is "
pending
". -
Run the following substeps state is "
terminated
" or "aborted
": -
If aborted and raceFetchController is not null, then:
-
Abort raceFetchController.
-
Set raceResponse to a race response whose value is null.
-
-
Resolve preloadResponse with undefined.
-
Run the following substeps in parallel:
-
Let fetchHandlerResponse be the result of Create Fetch Event and Dispatch with request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse, and raceResponse.
-
If fetchHandlerResponse is not null and not a abort raceFetchController.
-
Enqueue fetchHandlerResponse to queue.
-
-
Wait until queue is not empty.
-
Return the result of dequeue queue.
-
-
Assert: source is "
fetch-event
"
-
-
If request is a contains
fetch
, and registration’s active worker’s all fetch listeners are empty flag is not set then:Note: If the above is true except registration’s active worker’s set of event types to handle does not contain
fetch
, then the user agent may wish to show a console warning, as the developer’s intent isn’t clear.-
Let preloadRequest be the result of cloning the request request.
-
Let preloadRequestHeaders be preloadRequest’s header list.
-
Let preloadResponseObject be a new
guard is "
immutable
". -
value is registration’s navigation preload header value.
-
Set preloadRequest’s service-workers mode to "
none
". -
Let preloadFetchController be null.
-
Run the following substeps state is "
terminated
" or "aborted
":-
Set preloadFetchController to the result of fetching preloadRequest.
To processResponse for navigationPreloadResponse, run these substeps:
-
If navigationPreloadResponse’s type is "
error
", reject preloadResponse with aTypeError
and terminate these substeps. -
Associate preloadResponseObject with navigationPreloadResponse.
-
Resolve preloadResponse with preloadResponseObject.
-
-
-
If aborted, then:
-
Let deserializedError be the result of deserialize a serialized abort reason given null and workerRealm.
-
Abort preloadFetchController with deserializedError.
-
-
-
Else, resolve preloadResponse with undefined.
-
Return the result of Create Fetch Event and Dispatch with request, registration, useHighResPerformanceTimers, timingInfo, workerRealm, reservedClient, preloadResponse, and null.
Create Fetch Event and Dispatch
- Input
-
request, a request
registration, a service worker registration
useHighResPerformanceTimers, a boolean
timingInfo, a service worker timing info
workerRealm, a relevant realm of the global object
reservedClient, a reserved client
preloadResponse, a promise
raceResponse, a race response or null
- Output
-
a response
-
Let response be null.
-
Let eventCanceled be false.
-
Let client be request’s client.
-
Let activeWorker be registration’s active worker.
-
Let eventHandled be null.
-
Let handleFetchFailed be false.
-
Let respondWithEntered be false.
-
Let shouldSoftUpdate be true if any of the following are true, and false otherwise:
-
request is a non-subresource request.
-
request is a subresource request and registration is stale.
-
-
If the result of running the Should Skip Event algorithm with "fetch" and activeWorker is true, then:
-
If shouldSoftUpdate is true, then in parallel run the Soft Update algorithm with registration.
-
Return null.
-
-
If activeWorker’s all fetch listeners are empty flag is set:
-
-
If activeWorker’s state is "activating", then wait for activeWorker’s state to become "activated".
-
Run the Run Service Worker algorithm with activeWorker.
-
If shouldSoftUpdate is true, then run the Soft Update algorithm with registration.
-
-
Return null.
-
-
If useHighResPerformanceTimers is true, then set useHighResPerformanceTimers to activeWorker’s global object’s cross-origin isolated capability.
-
Let timingInfo’s start time be the coarsened shared current time given useHighResPerformanceTimers.
-
If activeWorker’s state is "
activating
", wait for activeWorker’s state to become "activated
". -
If the result of running the Run Service Worker algorithm with activeWorker is failure, then set handleFetchFailed to true.
-
Else:
-
Set workerRealm to the relevant realm of the activeWorker’s global object.
-
Set eventHandled to a new promise in workerRealm.
-
If raceResponse is not null, set activeWorker’s global object’s race response map[request] to raceResponse.
-
Queue a task task to run the following substeps:
-
Let e be the result of creating an event with
FetchEvent
. -
Let abortController be a AbortController object with workerRealm.
-
Let requestObject be the result of guard which is "
immutable
", abortController’s signal, and workerRealm. -
Initialize e’s
cancelable
attribute to true. -
Initialize e’s
request
attribute to requestObject. -
Initialize e’s
preloadResponse
to preloadResponse. -
If request is a id, and to the empty string otherwise.
-
If request is a replaces client id, and to the empty string otherwise.
-
Initialize e’s
handled
to eventHandled. -
Let timingInfo’s fetch event dispatch time to the coarsened shared current time given useHighResPerformanceTimers.
-
Dispatch e at activeWorker’s global object.
-
Invoke Update Service Worker Extended Events Set with activeWorker and e.
-
If e’s respond-with entered flag is set, set respondWithEntered to true.
-
If e’s wait to respond flag is set, then:
-
Wait until e’s wait to respond flag is unset.
-
If e’s respond-with error flag is set, set handleFetchFailed to true.
-
Else, set response to e’s potential response.
-
-
If response is null, request’s source is null, then:
-
If response is not null, then set response’s service worker timing info to timingInfo.
-
If e’s canceled flag is set, set eventCanceled to true.
-
If fetchController state is "
terminated
" or "aborted
", then:-
Let deserializedError be the result of serialized abort reason and workerRealm.
-
signal abort on abortController with deserializedError.
-
If task is discarded, set handleFetchFailed to true.
The task must use activeWorker’s event loop and the handle fetch task source.
-
-
-
Wait for task to have executed or for handleFetchFailed to be true.
-
If shouldSoftUpdate is true, then in parallel run the Soft Update algorithm with registration.
-
If activeWorker’s global object’s race response map[request] remove activeWorker’s global object’s race response map[request].
-
If respondWithEntered is false, then:
-
If eventCanceled is true, then:
-
If eventHandled is not null, then DOMException in workerRealm.
-
Return a network error.
-
-
If eventHandled is not null, then resolve eventHandled.
-
If raceResponse’s value is not null, then:
-
Return null.
-
-
If handleFetchFailed is true, then:
-
If eventHandled is not null, then DOMException in workerRealm.
-
Return a network error.
-
-
If eventHandled is not null, then resolve eventHandled.
-
Return response.
Parse URL Pattern
- Input
-
rawPattern, a
URLPatternCompatible
serviceWorker, a service worker
- Output
-
Let baseURL be serviceWorker’s script url.
-
Return the result of building a URL pattern from a Web IDL value rawPattern given baseURL.
Verify Router Condition
- Input
-
condition, a
RouterCondition
serviceWorker, a service worker
- Output
-
a boolean
-
Let hasCondition be false.
-
If condition["
urlPattern
"] exists, then:-
Let rawPattern be condition["
urlPattern
"]. -
Let pattern be the result of running the Parse URL Pattern algorithm passing rawPattern and serviceWorker. If this throws an exception, catch it and return false.
-
If pattern has regexp groups, then return false.
Note: Since running a user-defined regular expression has a security concern, it is prohibited.
-
Set hasCondition to true.
-
-
If condition["
requestMethod
"] exists:-
Let method be condition["
requestMethod
"]. -
If method is not a method, then return false.
-
If method is a forbidden method, then return false.
-
Set hasCondition to true.
-
-
If condition["
requestMode
"] exists, set hasCondition to true. -
If condition["
requestDestination
"] exists, set hasCondition to true. -
If condition["
runningStatus
"] exists, set hasCondition to true. -
If condition["
_or
"] exists, then:-
If hasCondition is true, return false.
Note: For ease of understanding the router rule, the "or" condition is mutually exclusive with other conditions.
-
Let orConditions be condition["
_or
"]. -
For each orCondition of orConditions:
-
If running the Verify Router Condition algorithm with orCondition and serviceWorker returns false, return false.
-
-
Set hasCondition to true.
-
-
If condition["
not
"] exists, then:-
If hasCondition is true, return false.
Note: For ease of understanding the router rule, the "not" condition is mutually exclusive with other conditions.
-
If running the Verify Router Condition algorithm with condition["
not
"] and serviceWorker returns false, return false. -
Set hasCondition to true.
-
-
Return hasCondition.
Match Router Condition
- Input
-
condition, a
RouterCondition
serviceWorker, a service worker
request, a request
- Output
-
a boolean
Note: if there are multiple conditions (e.g. urlPattern
, runningStatus
, and requestMethod
are set), all conditions need to match for true to be returned.
-
If condition["
or
"] exists, then:-
Let orConditions be condition["
or
"]. -
For each orCondition of orConditions:
-
If running the Match Router Condition algorithm with orCondition, serviceWorker and request returns true, then return true.
-
-
Return false.
-
-
If condition["
not
"] exists, then:-
If running the Match Router Condition algorithm with condition["
not
"], serviceWorker and request returns true, then return false. -
Return true.
-
-
Else:
Note: The Verify Router Condition algorithm guarantees that
or
,not
, and other conditions are mutually exclusive.-
If condition["
urlPattern
"] exists, then:-
Let rawPattern be condition["
urlPattern
"]. -
Let pattern be the result of running the Parse URL Pattern algorithm passing rawPattern and serviceWorker.
-
If running URL returns null, return false.
-
-
If condition["
requestMethod
"] exists, then:-
Let method be condition["
requestMethod
"]. -
Normalize method.
-
If request’s method is not method, return false.
-
-
If condition["
requestMode
"] exists, then:-
Let mode be condition["
requestMode
"]. -
If request’s mode is not mode, return false.
-
-
If condition["
requestDestination
"] exists, then:-
Let destination be condition["
requestDestination
"]. -
If request’s destination is not destination, return false.
-
-
If condition["
runningStatus
"] exists, then:-
Let runningStatus be condition["
runningStatus
"]. -
If runningStatus is
"running"
, and serviceWorker is not running, return false. -
If runningStatus is
"not-running"
, and serviceWorker is running, return false.
-
-
Return true.
-
Check Router Registration Limit
- Input
-
routerRules, a list of router rules
- Output
-
a boolean
Note: Router conditions can be complex and nested using _or
and not
. To prevent excessive processing, this algorithm introduces two limits. First, the total number of conditions, counting all nested conditions, cannot exceed 1024. Second, the nesting depth is limited to 10 levels to avoid exponential computation.
-
Let result be a count router condition result.
-
Set result’s condition count to 1024.
-
Set result’s quota exceeded to false.
-
For each rule of routerRules:
-
Set result to be the result of running Count Router Inner Conditions with rule["
condition
"], result, and 10. -
If result’s quota exceeded is true, return false.
-
-
Return true.
Count Router Inner Conditions
- Input
-
condition, a
RouterCondition
result, a count router condition result
depth, a number
- Output
-
result, a count router condition result
-
Decrement result’s condition count by one.
-
If result’s condition count is zero, or depth is zero, then:
-
Set result’s quota exceeded to be true.
-
Return result.
-
-
If condition["
_or
"] exists, then:-
Decrement depth by one.
-
For each orCondition of condition["
_or
"]:-
Set result to be the result of running Count Router Inner Conditions with orCondition, result, and depth.
-
If result’s quota exceeded is true, return result.
-
-
-
Else if condition["
not
"] exists, then:-
Decrement depth by one.
-
Set result to be the result of running Count Router Inner Conditions with condition["
not
"], result, and depth. -
If result’s quota exceeded is true, return result.
-
-
Return result.
Get Router Source
- Input
-
serviceWorker, a service worker
request, a request
- Output
-
RouterSource
or null
-
For each rule of serviceWorker’s list of router rules:
-
If running the Match Router Condition algorithm with rule["
condition
"], serviceWorker and request returns true, then return rule["source
"].
-
-
Return null.
Should Skip Event
- Input
-
eventName, a string
serviceWorker, a service worker
- Output
-
a boolean
Note: To avoid unnecessary delays, this specification permits skipping event dispatch when no event listeners for the event have been deterministically added in the service worker’s global during the very first script execution.
-
If serviceWorker’s set of event types to handle does not contain eventName, then the user agent may return true.
-
Return false.
Fire Functional Event
- Input
-
eventName, a string
eventConstructor, an event constructor that extends
ExtendableEvent
registration, a service worker registration
initialization, optional property initialization for event, constructed from eventConstructor
postDispatchSteps, optional steps to run on the active worker’s event loop, with dispatchedEvent set to the instance of eventConstructor that was dispatched.
- Output
-
None
-
Assert: registration’s active worker is not null.
-
Let activeWorker be registration’s active worker.
-
If the result of running Should Skip Event with eventName and activeWorker is true, then:
-
If registration is stale, then in parallel run the Soft Update algorithm with registration.
-
Return.
-
-
If activeWorker’s state is "
activating
", wait for activeWorker’s state to become "activated
". -
If the result of running the Run Service Worker algorithm with activeWorker is failure, then:
-
If registration is stale, then in parallel run the Soft Update algorithm with registration.
-
Return.
-
-
Queue a task task to run these substeps:
-
Let event be the result of relevant realm of activeWorker’s global object.
-
If initialization is not null, then initialize event with initialization.
-
Dispatch event on activeWorker’s global object.
-
Invoke Update Service Worker Extended Events Set with activeWorker and event.
-
If postDispatchSteps is not null, then run postDispatchSteps passing event as dispatchedEvent.
The task must use activeWorker’s event loop and the handle functional event task source.
-
-
Wait for task to have executed or been discarded.
-
If registration is stale, then in parallel run the Soft Update algorithm with registration.
amazingthing
" event (which is of type AmazingThingEvent
) on a particular serviceWorkerRegistration, and initialize the event object’s properties, the prose would be:
-
Fire Functional Event "
amazingthing
" usingAmazingThingEvent
on serviceWorkerRegistration with the following properties:- propertyName
-
value
- anotherPropertyName
-
anotherValue
Then run the following steps with dispatchedEvent:
-
Do whatever you need to with dispatchedEvent on the service worker’s event loop.
Note that the initialization steps and post-dispatch steps are optional. If they aren’t needed, the prose would be:
-
Fire Functional Event "
whatever
" usingExtendableEvent
on serviceWorkerRegistration.
Handle Service Worker Client Unload
The user agent must run these steps as part of when a service worker client unloads via unloading document cleanup steps or termination.
- Input
-
client, a service worker client
- Output
-
None
-
Run the following steps atomically.
-
Let registration be the service worker registration used by client.
-
If registration is null, abort these steps.
-
If any other service worker client is using registration, abort these steps.
-
If registration is unregistered, invoke Try Clear Registration with registration.
-
Invoke Try Activate with registration.
Handle User Agent Shutdown
- Input
-
None
- Output
-
None
-
-
If registration’s installing worker is not null, then:
-
If registration’s waiting worker is null and registration’s active worker is null, invoke Clear Registration with registration and continue to the next iteration of the loop.
-
Else, set registration’s installing worker to null.
-
-
If registration’s waiting worker is not null, then in parallel:
-
Invoke Activate with registration.
-
-
Update Service Worker Extended Events Set
- Input
-
worker, a service worker
event, an event
- Output
-
None
-
Assert: event’s dispatch flag is unset.
-
For each item of worker’s set of extended events:
-
If item is not active, remove item from worker’s set of extended events.
-
-
If event is active, append event to worker’s set of extended events.
Unregister
- Input
-
job, a job
- Output
-
none
-
If the origin, then:
-
Invoke Reject Job Promise with job and "
DOMException
. -
Invoke Finish Job with job and abort these steps.
-
-
Let registration be the result of running Get Registration given job’s storage key and job’s scope url.
-
If registration is null, then:
-
Invoke Resolve Job Promise with job and false.
-
Invoke Finish Job with job and abort these steps.
-
-
Remove registration map[(registration’s storage key, job’s scope url)].
-
Invoke Resolve Job Promise with job and true.
-
Invoke Try Clear Registration with registration.
Note: If Try Clear Registration does not trigger Clear Registration here, Clear Registration is tried again when the last client using the registration is unloaded or the extend lifetime promises for the registration’s service workers settle.
-
Invoke Finish Job with job.
Set Registration
- Input
-
storage key, a storage key
scope, a URL
updateViaCache, an update via cache mode
- Output
-
registration, a service worker registration
-
Run the following steps atomically.
-
Let scopeString be serialized scope with the exclude fragment flag set.
-
Let registration be a new service worker registration whose storage key is set to storage key, scope url is set to scope, and update via cache mode is set to updateViaCache.
-
Set registration map[(storage key, scopeString)] to registration.
-
Return registration.
Clear Registration
- Input
-
registration, a service worker registration
- Output
-
None
-
Run the following steps atomically.
-
If registration’s installing worker is not null, then:
-
Terminate registration’s installing worker.
-
Run the Update Worker State algorithm passing registration’s installing worker and "
redundant
" as the arguments. -
Run the Update Registration State algorithm passing registration, "
installing
" and null as the arguments.
-
-
If registration’s waiting worker is not null, then:
-
Terminate registration’s waiting worker.
-
Run the Update Worker State algorithm passing registration’s waiting worker and "
redundant
" as the arguments. -
Run the Update Registration State algorithm passing registration, "
waiting
" and null as the arguments.
-
-
If registration’s active worker is not null, then:
-
Terminate registration’s active worker.
-
Run the Update Worker State algorithm passing registration’s active worker and "
redundant
" as the arguments. -
Run the Update Registration State algorithm passing registration, "
active
" and null as the arguments.
-
Try Clear Registration
- Input
-
registration, a service worker registration
- Output
-
None
-
Invoke Clear Registration with registration if no service worker client is using registration and all of the following conditions are true:
-
registration’s installing worker is null or the result of running Service Worker Has No Pending Events with registration’s installing worker is true.
-
registration’s waiting worker is null or the result of running Service Worker Has No Pending Events with registration’s waiting worker is true.
-
registration’s active worker is null or the result of running Service Worker Has No Pending Events with registration’s active worker is true.
-
Update Registration State
- Input
-
registration, a service worker registration
target, a string (one of "
installing
", "waiting
", and "active
")source, a service worker or null
- Output
-
None
-
Let registrationObjects be an array containing all the
ServiceWorkerRegistration
objects associated with registration. -
If target is "
installing
", then:-
Set registration’s installing worker to source.
-
For each registrationObject in registrationObjects:
-
-
Else if target is "
waiting
", then:-
Set registration’s waiting worker to source.
-
For each registrationObject in registrationObjects:
-
-
Else if target is "
active
", then:-
Set registration’s active worker to source.
-
For each registrationObject in registrationObjects:
-
Update Worker State
- Input
-
worker, a service worker
state, a service worker state
- Output
-
None
-
Assert: state is not "
parsed
".Note: "
parsed
" is the initial state. A service worker is never updated to this state. -
Set worker’s state to state.
-
Let settingsObjects be all origin.
-
For each settingsObject of settingsObjects, DOM manipulation task source to run the following steps:
-
Let objectMap be settingsObject’s service worker object map.
-
If objectMap[worker] does not exist, then abort these steps.
-
Let workerObj be objectMap[worker].
-
Set workerObj’s
state
to state. -
Fire an event named
statechange
at workerObj.
-
Notify Controller Change
- Input
-
client, a service worker client
- Output
-
None
-
Assert: client is not null.
-
If client is an fire an event named
controllerchange
at theServiceWorkerContainer
object that client is associated with.
Match Service Worker Registration
- Input
-
storage key, a storage key
clientURL, a URL
- Output
-
Run the following steps atomically.
-
Let clientURLString be serialized clientURL.
-
Let matchingScopeString be the empty string.
-
Let scopeStringSet be an empty list.
-
keys:
-
If storage key append entry scope to the end of scopeStringSet.
-
-
Set matchingScopeString to the longest value in scopeStringSet which the value of clientURLString starts with, if it exists.
Note: The URL string matching in this step is prefix-based rather than path-structural. E.g. a client URL string with "https://example.com/prefix-of/resource.html" will match a registration for a scope with "https://example.com/prefix". The URL string comparison is safe for the same-origin security as HTTP(S) URLs are always serialized with a trailing slash at the end of the origin part of the URLs.
-
Let matchingScope be null.
-
If matchingScopeString is not the empty string, then:
-
Set matchingScope to the result of parsing matchingScopeString.
-
Assert: matchingScope’s same origin.
-
-
Return the result of running Get Registration given storage key and matchingScope.
Get Registration
- Input
-
storage key, a storage key
scope, a URL
- Output
-
Run the following steps atomically.
-
Let scopeString be the empty string.
-
If scope is not null, set scopeString to serialized scope with the exclude fragment flag set.
-
For each (entry storage key, entry scope) → registration of registration map:
-
If storage key equals entry storage key and scopeString matches entry scope, then return registration.
-
-
Return null.
Get Newest Worker
- Input
-
registration, a service worker registration
- Output
-
newestWorker, a service worker
-
Run the following steps atomically.
-
Let newestWorker be null.
-
If registration’s installing worker is not null, set newestWorker to registration’s installing worker.
-
Else if registration’s waiting worker is not null, set newestWorker to registration’s waiting worker.
-
Else if registration’s active worker is not null, set newestWorker to registration’s active worker.
-
Return newestWorker.
Service Worker Has No Pending Events
- Input
-
worker, a service worker
- Output
-
True or false, a boolean
-
For each event of worker’s set of extended events:
-
If event is active, return false.
-
-
Return true.
Create Client
- Input
-
client, a service worker client
- Output
-
clientObject, a
Client
object
-
Let clientObject be a new
Client
object. -
Set clientObject’s service worker client to client.
-
Return clientObject.
Create Window Client
- Input
-
client, a service worker client
frameType, a string
visibilityState, a string
focusState, a boolean
ancestorOriginsList, a list
- Output
-
windowClient, a
WindowClient
object
-
Let windowClient be a new
WindowClient
object. -
Set windowClient’s service worker client to client.
-
Set windowClient’s frame type to frameType.
-
Set windowClient’s visibility state to visibilityState.
-
Set windowClient’s focus state to focusState.
-
Set windowClient’s ancestor origins array to a frozen array created from ancestorOriginsList.
-
Return windowClient.
Get Frame Type
- Input
-
navigable, a navigable
- Output
-
frameType, a string
-
If navigable’s parent is not null, then return "
nested
". -
If navigable’s auxiliary browsing context, then return "
auxiliary
". -
Return "
top-level
".
Resolve Get Client Promise
- Input
-
client, a service worker client
promise, a promise
- Output
-
none
-
If client is an environment settings object, then:
-
If client is not a DOMException, on promise’s DOM manipulation task source, and abort these steps.
-
-
Else:
-
If client’s SecurityError"
DOM manipulation task source, and abort these steps.
-
-
If client is an environment settings object and is not a window client, then:
-
Let clientObject be the result of running Create Client algorithm with client as the argument.
-
DOM manipulation task source, and abort these steps.
-
-
Else:
-
Let browsingContext be null.
-
If client is an browsing context.
-
Else, set browsingContext to client’s target browsing context.
-
Let navigable be the active browsing context of browsingContext.
-
-
Let frameType be the result of running Get Frame Type with navigable.
-
Let visibilityState be browsingContext’s visibilityState attribute value.
-
Let focusState be the result of running the active document as the argument.
-
Let ancestorOriginsList be the empty list.
-
If client is a window client, set ancestorOriginsList to browsingContext’s ancestor origins list’s associated list.
-
-
If client’s discarded flag is set, resolve promise with undefined and abort these steps.
-
Let windowClient be the result of running Create Window Client with client, frameType, visibilityState, focusState, and ancestorOriginsList.
-
Resolve promise with windowClient.
-
-
-
Query Cache
- Input
-
requestQuery, a request
options, a
CacheQueryOptions
object, optionaltargetStorage, a request response list, optional
- Output
-
resultList, a request response list
-
Let resultList be an empty list.
-
Let storage be null.
-
If the optional argument targetStorage is omitted, set storage to the relevant request response list.
-
Else, set storage to targetStorage.
-
For each requestResponse of storage:
-
Let cachedRequest be requestResponse’s request.
-
Let cachedResponse be requestResponse’s response.
-
If Request Matches Cached Item with requestQuery, cachedRequest, cachedResponse, and options returns true, then:
-
Let requestCopy be a copy of cachedRequest.
-
Let responseCopy be a copy of cachedResponse.
-
Add requestCopy/responseCopy to resultList.
-
-
-
Return resultList.
Request Matches Cached Item
- Input
-
requestQuery, a request
request, a request
response, a response or null, optional, defaulting to null
options, a
CacheQueryOptions
object, optional - Output
-
a boolean
-
If options["
ignoreMethod
"] is false and request’s method is not `GET
`, return false. -
Let queryURL be requestQuery’s url.
-
Let cachedURL be request’s url.
-
If options["
ignoreSearch
"] is true, then: -
If queryURL does not equal cachedURL with the exclude fragment flag set, then return false.
-
If response is null, options["
ignoreVary
"] is true, or response’s contain `Vary
`, then return true. -
For each fieldValue in fieldValues:
-
If fieldValue matches "
*
", or the header list, then return false.
-
-
Return true.
Batch Cache Operations
- Input
-
operations, a list of cache batch operation objects
- Output
-
resultList, a request response list
-
Let cache be the relevant request response list.
-
Let backupCache be a new request response list that is a copy of cache.
-
Let addedItems be an empty list.
-
Try running the following substeps atomically:
-
Let resultList be an empty list.
-
For each operation in operations:
-
If operation’s type matches neither "
delete
" nor "put
", throw aTypeError
. -
If operation’s type matches "
delete
" and operation’s response is not null, throw aTypeError
. -
If the result of running Query Cache with operation’s request, operation’s options, and addedItems DOMException.
-
Let requestResponses be an empty list.
-
If operation’s type matches "
delete
", then:-
Set requestResponses to the result of running Query Cache with operation’s request and operation’s options.
-
For each requestResponse in requestResponses:
-
item whose value matches requestResponse from cache.
-
-
-
Else if operation’s type matches "
put
", then:-
If r’s throw a
TypeError
. -
If r’s throw a
TypeError
. -
Set requestResponses to the result of running Query Cache with operation’s request.
-
For each requestResponse of requestResponses:
-
item whose value matches requestResponse from cache.
-
-
If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, DOMException.
-
Append operation’s request/operation’s response to addedItems.
-
Append operation’s request/operation’s response to resultList.
-
-
Return resultList.
-
-
And then, if an exception was thrown, then:
-
items from the relevant request response list.
-
For each requestResponse of backupCache:
-
Append requestResponse to the relevant request response list.
-
-
Throw the exception.
Note: When an exception is thrown, the implementation does undo (roll back) any changes made to the cache storage during the batch operation job.
-
Is Async Module
- Input
-
record, a Module Record
moduleMap, a module map
base, a URL
seen, a URLs
- Output
-
a boolean
-
If record is not a Cyclic Module Record, then:
-
Return false.
-
-
If record.[[Async]] is true, then:
-
Return true.
-
-
For each string requested of record.[[RequestedModules]]:
-
Let url be the result of resolving a module specifier given base and requested.
-
Assert: url is never failure, because resolving a module specifier must have been previously successful with these same two arguments.
-
If seen does not contain url, then:
-
Append url to seen.
-
If moduleMap[url] does not have a record, then:
-
Return false.
-
-
If Is Async Module for moduleMap[url]'s record, moduleMap, base, and seen is true, then:
-
Return true.
-
-
-
-
Return false.
Lookup Race Response
-
Let registration be null.
-
If request is a non-subresource request, then:
-
If request’s reserved client is null, return null.
-
Let storage key be the result of running reserved client.
-
Set registration to the result of running Match Service Worker Registration given storage key and request’s url.
-
-
Else if request is a subresource request, then:
-
Let client be request’s client.
-
If client’s active service worker is null, return null.
-
Set registration to client’s active service worker’s containing service worker registration.
-
-
Otherwise, return null.
-
Let activeWorker be registration’s active worker.
-
Let map be activeWorker’s global object’s race response map.
-
If map[request] exists, then:
-
Return null.
Appendix B: Extended HTTP headers
Service Worker Script Request
An HTTP request to header:
- `
Service-Worker
` -
Indicates this request is a service worker’s script resource request.
Note: 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.
Note: The value is a URL. If a relative URL is given, it is parsed against the script’s URL.
/ Maximum allowed scope defaults to the path the script sits in / "/js/" in this example navigator. serviceWorker. register( "/js/sw.js" ). then(() => { console. log( "Install succeeded with the default scope '/js/'." ); });
/ 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 (() => { console. error( "Install failed due to the path restriction violation." ); });
/ Set the scope to an upper path of the script location / Response included "Service-Worker-Allowed : /" navigator. serviceWorker. register( "/js/sw.js" , { scope: "/" }). then(() => { console. log( "Install succeeded as the max allowed scope was overriden to '/'." ); });
/ 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 (() => { 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
Note: The validation of the Service-Worker-Allowed header’s values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.
8. 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, Jinho Bang, Yutaka Hirano, Michael(tm) Smith, isonmad, Ali Alabbas, Philip Jägenstedt, Mike Pennisi, and Eric Willigers.
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.