From 9889d02307a53b1bc0f6f8e85c8fef8a834f2282 Mon Sep 17 00:00:00 2001
From: Jungkee Song The value of Resolve Job Promise
: Input
- :: |job|, a job
+ :: |job|, a [=job=]
:: |value|, any
: Output
:: none
- 1. If |job|'s [=job/client=] is not null, queue a task to resolve |job|'s [=job/job promise=] with |value| on |job|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.
+ 1. Let |convertedValue| be null.
+ 1. If |job|'s [=job/client=] is not null, [=queue a task=], on |job|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to run the following substeps:
+ 1. If |job|'s [=job/job type=] is either *register* or *update*, set |convertedValue| to the {{ServiceWorkerRegistration}} object that represents |value|, in |job|'s [=job/client=]'s [=environment settings object/Realm=].
+ 1. Else, set |convertedValue| to |value|, in |job|'s [=job/client=]'s [=environment settings object/Realm=].
+ 1. Resolve |job|'s [=job/job promise=] with |convertedValue|.
1. For each |equivalentJob| in |job|'s list of equivalent jobs:
- 1. If |equivalentJob|'s [=job/client=] is not null, queue a task to resolve |equivalentJob|'s [=job/job promise=] with |value| on |equivalentJob|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.
+ 1. If |equivalentJob|'s [=job/client=] is null, continue to the next iteration of the loop.
+ 1. [=Queue a task=], on |equivalentJob|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to run the following substeps:
+ 1. If |equivalentJob|'s [=job/job type=] is either *register* or *update*, set |convertedValue| to the {{ServiceWorkerRegistration}} object that represents |value|, in |equivalentJob|'s [=job/client=]'s [=environment settings object/Realm=].
+ 1. Else, set |convertedValue| to |value|, in |equivalentJob|'s [=job/client=]'s [=environment settings object/Realm=].
+ 1. Resolve |equivalentJob|'s [=job/job promise=] with |convertedValue|.
Reject Job Promise
: Input
- :: |job|, a job
- :: |reason|, an exception
+ :: |job|, a [=job=]
+ :: |reason|, an [=exception=]
: Output
:: none
- 1. If |job|'s [=job/client=] is not null, queue a task to reject |job|'s [=job/job promise=] with |reason| on |job|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.
- 1. For each |equivalentJob| in |job|'s list of equivalent jobs:
- 1. If |equivalentJob|'s [=job/client=] is not null, queue a task to reject |equivalentJob|'s [=job/job promise=] with |reason| on |equivalentJob|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.
+ 1. If |job|'s [=job/client=] is not null, [=queue a task=], on |job|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to reject |job|'s [=job/job promise=] with an exception that is a copy of |reason|, in |job|'s [=job/client=]'s [=environment settings object/Realm=].
+ 1. For each |equivalentJob| in |job|'s [=list of equivalent jobs=]:
+ 1. If |equivalentJob|'s [=job/client=] is null, continue to the next iteration of the loop:
+ 1. [=Queue a task=], on |equivalentJob|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to reject |equivalentJob|'s [=job/job promise=] with an exception that is a copy of |reason|, in |equivalentJob|'s [=job/client=]'s [=environment settings object/Realm=].
installing
" and |worker| as the arguments.
1. Run the Update Worker State algorithm passing |registration|'s installing worker and *installing* as the arguments.
1. Assert: |job|'s [=job/job promise=] is not null.
- 1. Invoke Resolve Job Promise with |job| and the {{ServiceWorkerRegistration}} object which represents |registration|.
+ 1. Invoke [=Resolve Job Promise=] with |job| and |registration|.
1. Queue a task to fire an event named updatefound
at all the {{ServiceWorkerRegistration}} objects for all the [=/service worker clients=] whose creation URL matches |registration|'s [=service worker registration/scope url=] and all the [=/service workers=] whose containing service worker registration is |registration|.
1. Let |installingWorker| be |registration|'s installing worker.
1. Invoke Run Service Worker algorithm given |installingWorker|, and with the *force bypass cache for importscripts flag* set if |job|'s [=job/force bypass cache flag=] is set.
diff --git a/docs/index.html b/docs/index.html
index 358a491f..cdf787d2 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1177,7 +1177,7 @@
}
}
-
+
+.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
+code.highlight { padding: .1em; border-radius: .3em; }
+pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
+.highlight .c { color: #708090 } /* Comment */
+.highlight .k { color: #990055 } /* Keyword */
+.highlight .l { color: #000000 } /* Literal */
+.highlight .n { color: #0077aa } /* Name */
+.highlight .o { color: #999999 } /* Operator */
+.highlight .p { color: #999999 } /* Punctuation */
+.highlight .cm { color: #708090 } /* Comment.Multiline */
+.highlight .cp { color: #708090 } /* Comment.Preproc */
+.highlight .c1 { color: #708090 } /* Comment.Single */
+.highlight .cs { color: #708090 } /* Comment.Special */
+.highlight .kc { color: #990055 } /* Keyword.Constant */
+.highlight .kd { color: #990055 } /* Keyword.Declaration */
+.highlight .kn { color: #990055 } /* Keyword.Namespace */
+.highlight .kp { color: #990055 } /* Keyword.Pseudo */
+.highlight .kr { color: #990055 } /* Keyword.Reserved */
+.highlight .kt { color: #990055 } /* Keyword.Type */
+.highlight .ld { color: #000000 } /* Literal.Date */
+.highlight .m { color: #000000 } /* Literal.Number */
+.highlight .s { color: #a67f59 } /* Literal.String */
+.highlight .na { color: #0077aa } /* Name.Attribute */
+.highlight .nc { color: #0077aa } /* Name.Class */
+.highlight .no { color: #0077aa } /* Name.Constant */
+.highlight .nd { color: #0077aa } /* Name.Decorator */
+.highlight .ni { color: #0077aa } /* Name.Entity */
+.highlight .ne { color: #0077aa } /* Name.Exception */
+.highlight .nf { color: #0077aa } /* Name.Function */
+.highlight .nl { color: #0077aa } /* Name.Label */
+.highlight .nn { color: #0077aa } /* Name.Namespace */
+.highlight .py { color: #0077aa } /* Name.Property */
+.highlight .nt { color: #669900 } /* Name.Tag */
+.highlight .nv { color: #222222 } /* Name.Variable */
+.highlight .ow { color: #999999 } /* Operator.Word */
+.highlight .mb { color: #000000 } /* Literal.Number.Bin */
+.highlight .mf { color: #000000 } /* Literal.Number.Float */
+.highlight .mh { color: #000000 } /* Literal.Number.Hex */
+.highlight .mi { color: #000000 } /* Literal.Number.Integer */
+.highlight .mo { color: #000000 } /* Literal.Number.Oct */
+.highlight .sb { color: #a67f59 } /* Literal.String.Backtick */
+.highlight .sc { color: #a67f59 } /* Literal.String.Char */
+.highlight .sd { color: #a67f59 } /* Literal.String.Doc */
+.highlight .s2 { color: #a67f59 } /* Literal.String.Double */
+.highlight .se { color: #a67f59 } /* Literal.String.Escape */
+.highlight .sh { color: #a67f59 } /* Literal.String.Heredoc */
+.highlight .si { color: #a67f59 } /* Literal.String.Interpol */
+.highlight .sx { color: #a67f59 } /* Literal.String.Other */
+.highlight .sr { color: #a67f59 } /* Literal.String.Regex */
+.highlight .s1 { color: #a67f59 } /* Literal.String.Single */
+.highlight .ss { color: #a67f59 } /* Literal.String.Symbol */
+.highlight .vc { color: #0077aa } /* Name.Variable.Class */
+.highlight .vg { color: #0077aa } /* Name.Variable.Global */
+.highlight .vi { color: #0077aa } /* Name.Variable.Instance */
+.highlight .il { color: #000000 } /* Literal.Number.Integer.Long */
+
Service Workers Nightly
- Editor’s Draft,
+ Editor’s Draft,
Bootstrapping with a service worker:
// scope defaults to the path the script sits in
-// "/" in this example
-navigator.serviceWorker.register("/serviceworker.js").then(registration => {
- console.log("success!");
+// "/" in this example
+
navigator.serviceWorker.register("/serviceworker.js").then(registration => {
+ console.log("success!");
if (registration.installing) {
- registration.installing.postMessage("Howdy from your installing page.");
+ registration.installing.postMessage("Howdy from your installing page.");
}
-}, err => {
- console.error("Installing the worker failed!", err);
-});
+}, err => {
+ console.error("Installing the worker failed!", err);
+});
For example, consider a document created by a navigation to
https://example.com/app.html
which matches via the following registration call which has been previously executed:
// Script on the page https://example.com/app.html
-navigator.serviceWorker.register("/service_worker.js");
+
navigator.serviceWorker.register("/service_worker.js");
navigator.serviceWorker.controller.scriptURL
will be "https://example.com/service_worker.js
".
Serving Cached Resources:
// caching.js
-self.addEventListener("install", event => {
+
self.addEventListener("install", event => {
event.waitUntil(
// Open a cache of resources.
- caches.open("shell-v1").then(cache => {
+ caches.open("shell-v1").then(cache => {
// Begins the process of fetching them.
// The coast is only clear when all the resources are ready.
- return cache.addAll([
+ 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 => {
+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");
- })
- );
-});
+ caches.match(e.request).then(response => {
+ return response || fetch(e.request);
+ }).catch(() => {
+ return caches.match("/fallback.html");
+ })
+ );
+});
A service worker registration and its scope url are created by a serviceworker link, which is declared using a "serviceworker"
Link
header or a link
element whose rel
attribute contains the keyword "serviceworker
".
Link
headerA serviceworker link can be declared using a Link
header [RFC5988] with "serviceworker
" as the value of the "rel
" parameter and a serialized script url inside angle brackets ("<>
")as the target IRI, and the following optional target attributes:
A serviceworker link can be declared using a Link
header [RFC5988] with "serviceworker
" as the value of the "rel
" parameter and a serialized script url inside angle brackets ("<>
") as the target IRI, and the following optional target attributes:
scope
has more or less the same effect as a document being loaded in a secure context with the following link
element:
<link rel="serviceworker" href="/js/sw.js" scope="/"> +<link rel="serviceworker" href="/js/sw.js" scope="/">which is more or less equivalent to the page containing JavaScript code like:
-navigator.serviceWorker.register("/js/sw.js", { scope: "/" }); +navigator.serviceWorker.register("/js/sw.js", { scope: "/" });
If job’s client is not null, queue a task to resolve job’s job promise with value on job’s client's responsible event loop using the DOM manipulation task source as the task source.
+Let convertedValue be null.
+If job’s client is not null, queue a task, on job’s client's responsible event loop using the DOM manipulation task source, to run the following substeps:
+If job’s job type is either register or update, set convertedValue to the ServiceWorkerRegistration
object that represents value, in job’s client's Realm.
Resolve job’s job promise with convertedValue.
+For each equivalentJob in job’s list of equivalent jobs:
If equivalentJob’s client is not null, queue a task to resolve equivalentJob’s job promise with value on equivalentJob’s client's responsible event loop using the DOM manipulation task source as the task source.
+If equivalentJob’s client is null, continue to the next iteration of the loop.
+Queue a task, on equivalentJob’s client's responsible event loop using the DOM manipulation task source, to run the following substeps:
+If equivalentJob’s job type is either register or update, set convertedValue to the ServiceWorkerRegistration
object that represents value, in equivalentJob’s client's Realm.
Else, set convertedValue to value, in equivalentJob’s client's Realm.
+Resolve equivalentJob’s job promise with convertedValue.
+If job’s client is not null, queue a task to reject job’s job promise with reason on job’s client's responsible event loop using the DOM manipulation task source as the task source.
+If job’s client is not null, queue a task, on job’s client's responsible event loop using the DOM manipulation task source, to reject job’s job promise with an exception that is a copy of reason, in job’s client's Realm.
For each equivalentJob in job’s list of equivalent jobs:
If equivalentJob’s client is not null, queue a task to reject equivalentJob’s job promise with reason on equivalentJob’s client's responsible event loop using the DOM manipulation task source as the task source.
+If equivalentJob’s client is null, continue to the next iteration of the loop:
+Queue a task, on equivalentJob’s client's responsible event loop using the DOM manipulation task source, to reject equivalentJob’s job promise with an exception that is a copy of reason, in equivalentJob’s client's Realm.
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
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’s script url does not equal job’s script url with the exclude fragments flag set, then:
+If job’s job type is update, and newestWorker’s script url does not equal job’s script url with the exclude fragments flag set, then:
Invoke Reject Job Promise with job and a TypeError
.
classic
"
Fetch a classic worker script given job’s serialized script url, job’s client, "serviceworker
", and the to-be-created environment settings object for this service worker.
Fetch a classic worker script given job’s serialized script url, job’s client, "serviceworker
", and the to-be-created environment settings object for this service worker.
module
"
Fetch a module worker script graph given job’s serialized script url, job’s client, "serviceworker
", "omit
", and the to-be-created environment settings object for this service worker.
Fetch a module worker script graph given job’s serialized script url, job’s client, "serviceworker
", "omit
", and the to-be-created environment settings object for this service worker.
To perform the fetch given request, run the following steps:
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
Invoke Finish Job with job and abort these steps.
Assert: job’s job promise is not null.
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
Queue a task to fire an event named updatefound
at all the ServiceWorkerRegistration
objects for all the service worker clients whose creation URL matches registration’s scope url and all the service workers whose containing service worker registration is registration.
Queue a task to fire an event named updatefound
at all the ServiceWorkerRegistration
objects for all the service worker clients whose creation URL matches registration’s scope url and all the service workers whose containing service worker registration is registration.
Let installingWorker be registration’s installing worker.
If the origin of job’s scope url is not job’s client's origin, then:
+If the origin of job’s scope url is not job’s client's origin, then:
Invoke Reject Job Promise with job and a "SecurityError
" exception.
Let registrationObjects be an array containing all the ServiceWorkerRegistration
objects associated with registration.
Let registrationObjects be an array containing all the ServiceWorkerRegistration
objects associated with registration.
If target is "installing
", then:
// 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'."); -}); +// "/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."); -}); +// 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 '/'."); -}); +// 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."); -}); +// 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."); +});
If job’s client is not null, queue a task to resolve job’s job promise with value on job’s client's responsible event loop using the DOM manipulation task source as the task source.
+Let convertedValue be null.
+If job’s client is not null, queue a task, on job’s client's responsible event loop using the DOM manipulation task source, to run the following substeps:
+If job’s job type is either register or update, set convertedValue to the ServiceWorkerRegistration
object that represents value, in job’s client's Realm.
Resolve job’s job promise with convertedValue.
+For each equivalentJob in job’s list of equivalent jobs:
If equivalentJob’s client is not null, queue a task to resolve equivalentJob’s job promise with value on equivalentJob’s client's responsible event loop using the DOM manipulation task source as the task source.
+If equivalentJob’s client is null, continue to the next iteration of the loop.
+Queue a task, on equivalentJob’s client's responsible event loop using the DOM manipulation task source, to run the following substeps:
+If equivalentJob’s job type is either register or update, set convertedValue to the ServiceWorkerRegistration
object that represents value, in equivalentJob’s client's Realm.
Else, set convertedValue to value, in equivalentJob’s client's Realm.
+Resolve equivalentJob’s job promise with convertedValue.
+If job’s client is not null, queue a task to reject job’s job promise with reason on job’s client's responsible event loop using the DOM manipulation task source as the task source.
+If job’s client is not null, queue a task, on job’s client's responsible event loop using the DOM manipulation task source, to reject job’s job promise with an exception that is a copy of reason, in job’s client's Realm.
For each equivalentJob in job’s list of equivalent jobs:
If equivalentJob’s client is not null, queue a task to reject equivalentJob’s job promise with reason on equivalentJob’s client's responsible event loop using the DOM manipulation task source as the task source.
+If equivalentJob’s client is null, continue to the next iteration of the loop:
+Queue a task, on equivalentJob’s client's responsible event loop using the DOM manipulation task source, to reject equivalentJob’s job promise with an exception that is a copy of reason, in equivalentJob’s client's Realm.
If the origin of job’s script url is not job’s client's origin, then:
+If the origin of job’s script url is not job’s client's origin, then:
Invoke Reject Job Promise with job and a "SecurityError
" exception.
If the origin of job’s scope url is not job’s client's origin, then:
+If the origin of job’s scope url is not job’s client's origin, then:
Invoke Reject Job Promise with job and a "SecurityError
" exception.
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
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’s script url does not equal job’s script url with the exclude fragments flag set, then:
+If job’s job type is update, and newestWorker’s script url does not equal job’s script url with the exclude fragments flag set, then:
Invoke Reject Job Promise with job and a TypeError
.
classic
"
Fetch a classic worker script given job’s serialized script url, job’s client, "serviceworker
", and the to-be-created environment settings object for this service worker.
Fetch a classic worker script given job’s serialized script url, job’s client, "serviceworker
", and the to-be-created environment settings object for this service worker.
module
"
Fetch a module worker script graph given job’s serialized script url, job’s client, "serviceworker
", "omit
", and the to-be-created environment settings object for this service worker.
Fetch a module worker script graph given job’s serialized script url, job’s client, "serviceworker
", "omit
", and the to-be-created environment settings object for this service worker.
To perform the fetch given request, run the following steps:
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
Invoke Finish Job with job and abort these steps.
Assert: job’s job promise is not null.
Invoke Resolve Job Promise with job and the ServiceWorkerRegistration
object which represents registration.
Invoke Resolve Job Promise with job and registration.
Queue a task to fire an event named updatefound
at all the ServiceWorkerRegistration
objects for all the service worker clients whose creation URL matches registration’s scope url and all the service workers whose containing service worker registration is registration.
Queue a task to fire an event named updatefound
at all the ServiceWorkerRegistration
objects for all the service worker clients whose creation URL matches registration’s scope url and all the service workers whose containing service worker registration is registration.
Let installingWorker be registration’s installing worker.
If the origin of job’s scope url is not job’s client's origin, then:
+If the origin of job’s scope url is not job’s client's origin, then:
Invoke Reject Job Promise with job and a "SecurityError
" exception.
Let registrationObjects be an array containing all the ServiceWorkerRegistration
objects associated with registration.
Let registrationObjects be an array containing all the ServiceWorkerRegistration
objects associated with registration.
If target is "installing
", then:
// 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'."); -}); +// "/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."); -}); +// 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 '/'."); -}); +// 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."); -}); +// 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."); +});