From f1a1120ff07120a2e8f311fb61f429c9a74db1ef Mon Sep 17 00:00:00 2001 From: Jungkee Song Date: Thu, 16 Feb 2017 18:57:45 +0900 Subject: [PATCH] Improve Activate with Try Activate (#1065) This adds concepts and algorithms to track events (all service worker events: lifecycle events, functional events, extendable message events) that have pending extension promises so they can be used to check if the registration's waiting worker can be promoted. This also changes Install algorithm and related steps to match to the implementations behavior. That is, instead of waiting for the promotion condition in Install algorithm, newly introduced Try Activate algorithm just tries to activate depending on the condition and return. Try Activate is called when: - A service worker is installed. - The last client controlled by the existing active worker is unloaded. - skipWaiting() is called. - The extend lifetime promises for the existing active worker settle. Related issue: #916. --- docs/index.bs | 107 ++++++-- docs/index.html | 647 ++++++++++++++++++++++++++++----------------- docs/v1/index.bs | 98 +++++-- docs/v1/index.html | 603 ++++++++++++++++++++++++++---------------- 4 files changed, 918 insertions(+), 537 deletions(-) diff --git a/docs/index.bs b/docs/index.bs index 9d5e08b9..ede56461 100644 --- a/docs/index.bs +++ b/docs/index.bs @@ -168,6 +168,8 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe A [=/service worker=] has an associated set of event types to handle (a [=ordered set|set=]) whose [=item=] is an event listener's event type. It is initially an empty set. + A [=/service worker=] has an associated set of extended events (a [=ordered set|set=]) whose [=item=] is an {{ExtendableEvent}}. It is initially an empty set. + A [=/service worker=] has an associated list of foreign fetch scopes whose element type is a [=/URL=]. It is initially empty. A [=/service worker=] has an associated list of foreign fetch origins whose element type is a [=/URL=]. It is initially empty. @@ -364,6 +366,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Else, let it be initialized to a new {{Client}} object that represents the worker associated with |incumbentGlobal|. 1. Let the {{ExtendableMessageEvent/ports}} attribute of |e| be initialized to |newPorts|. 1. Dispatch |e| at |destination|. + 1. Invoke [=Update Service Worker Extended Events Set=] with |serviceWorker| and |e|. The task *must* use the DOM manipulation task source. @@ -903,7 +906,8 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Let |promise| be a new promise. 1. Run the following substeps in parallel: - 1. Set [=/service worker=]'s skip waiting flag. + 1. Set [=ServiceWorkerGlobalScope/service worker=]'s skip waiting flag. + 1. Invoke [=Try Activate=] with [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. 1. Resolve |promise| with undefined. 1. Return |promise|. @@ -1313,11 +1317,13 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe Note: If no lifetime extension promise has been added in the task that called the event handlers), calling {{ExtendableEvent/waitUntil()}} in subsequent asynchronous tasks will throw. 1. Add |f| to the [=ExtendableEvent/extend lifetime promises=]. - 1. Increase the [=ExtendableEvent/pending promises count=] by one. + 1. Increment the [=ExtendableEvent/pending promises count=] by one. - Note: The [=ExtendableEvent/pending promises count=] is increased even if the given promise has already been settled. The corresponding count decrease is done in the microtask queued by the reaction to the promise. + Note: The [=ExtendableEvent/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. - 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |f|, [=queue a microtask=] to decrease the [=ExtendableEvent/pending promises count=] by one. + 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |f|, [=queue a microtask=] to run these substeps: + 1. Decrement the [=ExtendableEvent/pending promises count=] by one. + 1. Invoke [=Try Activate=] with the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. The user agent *should not* terminate the [=/service worker=] associated with |event|'s relevant settings object's [=environment settings object/global object=] when |event|'s [=dispatch flag=] is set or |event|'s [=ExtendableEvent/pending promises count=] is not zero. However, the user agent *may* impose a time limit to this lifetime extension. @@ -1452,11 +1458,13 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. Add |r| to the extend lifetime promises. - 1. Increase the [=ExtendableEvent/pending promises count=] by one. + 1. Increment the [=ExtendableEvent/pending promises count=] by one. - Note: The [=ExtendableEvent/pending promises count=] is increased even if the given promise has already been settled. The corresponding count decrease is done in the microtask queued by the reaction to the promise. + Note: The [=ExtendableEvent/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. - 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to decrease the [=ExtendableEvent/pending promises count=] by one. + 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to run these substeps: + 1. Decrement the [=ExtendableEvent/pending promises count=] by one. + 1. Invoke [=Try Activate=] with the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. Note: {{FetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called. @@ -1568,11 +1576,13 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. Add |r| to the extend lifetime promises. - 1. Increase the [=ExtendableEvent/pending promises count=] by one. + 1. Increment the [=ExtendableEvent/pending promises count=] by one. - Note: The [=ExtendableEvent/pending promises count=] is increased even if the given promise has already been settled. The corresponding count decrease is done in the microtask queued by the reaction to the promise. + Note: The [=ExtendableEvent/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. - 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to decrease the [=ExtendableEvent/pending promises count=] by one. + 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to run these substeps: + 1. Decrement the [=ExtendableEvent/pending promises count=] by one. + 1. Invoke [=Try Activate=] with the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. Note: {{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called. @@ -2684,7 +2694,6 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Let |installFailed| be false. 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. - 1. Let |redundantWorker| be null. 1. Run the Update Registration State algorithm passing |registration|, "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. @@ -2705,24 +2714,22 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Wait for |task| to have executed or been discarded. 1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete. 1. If |installFailed| is true, then: - 1. Set |redundantWorker| to |registration|'s installing worker. + 1. Run the Update Worker State algorithm passing |registration|'s [=installing worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. - 1. Run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. If |newestWorker| is null, invoke Clear Registration algorithm passing |registration| as its argument. 1. Invoke Finish Job with |job| and abort these steps. 1. Set |registration|'s installing worker's imported scripts updated flag. 1. If |registration|'s waiting worker is not null, then: - 1. Set |redundantWorker| to |registration|'s waiting worker. - 1. Terminate |redundantWorker|. - 1. The user agent *may* abort in-flight requests triggered by |redundantWorker|. + 1. [=Terminate Service Worker|Terminate=] |registration|'s [=waiting worker=]. + 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=waiting worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and |registration|'s installing worker as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. 1. Run the Update Worker State algorithm passing |registration|'s waiting worker and *installed* as the arguments. - 1. If |redundantWorker| is not null, run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. Invoke Finish Job with |job|. 1. Wait for all the tasks queued by Update Worker State invoked in this algorithm have executed. - 1. Wait until no [=/service worker client=] is using |registration| or |registration|'s waiting worker's skip waiting flag is set. - 1. If |registration|'s waiting worker is not null, invoke Activate algorithm with |registration| as its argument. + 1. 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 [=Handle Service Worker Client Unload|unloaded=], {{ServiceWorkerGlobalScope/skipWaiting()}} is asynchronously called, and the [=extend lifetime promises=] for the existing [=active worker=] settle.
@@ -2734,18 +2741,15 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe :: None 1. If |registration|'s waiting worker is null, abort these steps. - 1. Let |redundantWorker| be null. - 1. If |registration|'s active worker is not null, then: - 1. Set |redundantWorker| to |registration|'s active worker. - 1. Wait for |redundantWorker| to finish handling any in-progress requests. - 1. Terminate |redundantWorker|. + 1. If |registration|'s [=active worker=] is not null, then: + 1. [=Terminate Service Worker|Terminate=] |registration|'s [=active worker=]. + 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=active worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "active" and |registration|'s waiting worker as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. 1. 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. - 1. If |redundantWorker| is not null, run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. For each [=/service worker client=] |client| whose creation URL matches |registration|'s [=service worker registration/scope url=]: 1. If |client| is a window client, unassociate |client|'s responsible document from its application cache, if it has one. 1. Else if |client| is a shared worker client, unassociate |client|'s [=environment settings object/global object=] from its application cache, if it has one. @@ -2767,6 +2771,20 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. 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 + + 1. If |registration|'s [=waiting worker=] is null, return. + 1. 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. +
+

Run Service Worker

@@ -2839,6 +2857,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. If |serviceWorker| is not running, abort these steps. 1. Let |serviceWorkerGlobalScope| be |serviceWorker|'s [=service worker/global object=]. 1. Set |serviceWorkerGlobalScope|'s closing flag to true. + 1. [=set/Remove=] all the [=items=] from |serviceWorker|'s [=set of extended events=]. 1. If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in |serviceWorkerGlobalScope|'s event loop's [=/task queues=], queue them to |serviceWorker|'s containing service worker registration's corresponding [=service worker registration/task queues=] in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from |serviceWorkerGlobalScope|'s event loop's [=/task queues=] without processing them. 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. @@ -2926,6 +2945,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. If |request| is a non-subresource request and |request|'s [=request/destination=] is not {{RequestDestination/"report"}}, initialize |e|'s {{FetchEvent/reservedClientId}} attribute to |reservedClient|'s [=environment/id=], and to the empty string otherwise. 1. If |request| is a navigation request, initialize |e|'s {{FetchEvent/targetClientId}} attribute to |request|'s [=request/target client id=], and to the empty string otherwise. 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. + 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |e|. 1. If |e|'s [=FetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true. 1. If |e|'s [=FetchEvent/wait to respond flag=] is set, then: 1. Wait until |e|'s [=FetchEvent/wait to respond flag=] is unset. @@ -2993,6 +3013,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Initialize |e|’s {{ForeignFetchEvent/request}} attribute to |r|. 1. Initialize |e|’s {{ForeignFetchEvent/origin}} attribute to the Unicode serialization of |request|'s [=request/origin=]. 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. + 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |e|. 1. If |e|'s [=ForeignFetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true. 1. If |e|'s wait to respond flag is set, wait until |e|'s wait to respond flag is unset. 1. Let |internalResponse| be |e|'s [=ForeignFetchEvent/potential response=]. @@ -3054,6 +3075,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Invoke Run Service Worker algorithm with |activeWorker| as the argument. 1. Queue a task |task| to run these substeps: 1. Invoke |callbackSteps| with |activeWorker|'s [=service worker/global object=] as its argument. + 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |event|. The |task| *must* use |activeWorker|'s event loop and the handle functional event task source. @@ -3076,7 +3098,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. If |registration| is null, abort these steps. 1. If any other [=/service worker client=] is using |registration|, abort these steps. 1. If |registration|'s uninstalling flag is set, invoke Clear Registration algorithm passing |registration| as its argument and abort these steps. - 1. If |registration|'s waiting worker is not null, run Activate algorithm with |registration| as the argument. + 1. If |registration|'s waiting worker is not null, invoke [=Try Activate=] with |registration|.
@@ -3095,6 +3117,21 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Invoke Activate with |registration|.
+
+

Update Service Worker Extended Events Set

+ + : Input + :: |worker|, a [=/service worker=] + :: |event|, an [=event=] + : Output + :: None + + 1. Assert: |event|'s [=dispatch flag=] is unset. + 1. For each |item| of |worker|'s [=set of extended events=]: + 1. If |item|'s [=pending promises count=] is zero, [=set/remove=] |item| from |worker|'s [=set of extended events=]. + 1. If |event|'s [=pending promises count=] is not zero, [=set/append=] |event| to |worker|'s [=set of extended events=]. +
+

Unregister

@@ -3148,19 +3185,16 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. If |registration|'s installing worker is not null, then: 1. Set |redundantWorker| to |registration|'s installing worker. 1. Terminate |redundantWorker|. - 1. The user agent *may* abort in-flight requests triggered by |redundantWorker|. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. 1. Run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. If |registration|'s waiting worker is not null, then: 1. Set |redundantWorker| to |registration|'s waiting worker. 1. Terminate |redundantWorker|. - 1. The user agent *may* abort in-flight requests triggered by |redundantWorker|. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. 1. Run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. If |registration|'s active worker is not null, then: 1. Set |redundantWorker| to |registration|'s active worker. 1. Terminate |redundantWorker|. - 1. The user agent *may* abort in-flight requests triggered by |redundantWorker|. 1. Run the Update Registration State algorithm passing |registration|, "active" and null as the arguments. 1. Run the Update Worker State algorithm passing |redundantWorker| and *redundant* as the arguments. 1. Let |scopeString| be serialized |registration|'s [=service worker registration/scope url=] with the *exclude fragment flag* set. @@ -3328,6 +3362,21 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Return |newestWorker|.
+
+

Service Worker Has No Pending Events

+ + : Input + :: |worker|, a [=/service worker=] + : Output + :: True or false, a boolean + + 1. Let |sum| be zero. + 1. For each |item| of |worker|'s [=set of extended events=]: + 1. Add |item|'s [=pending promises count=] to |sum|. + 1. If |sum| is zero, return true. + 1. Else, return false. +
+

Create Client

diff --git a/docs/index.html b/docs/index.html index 596322dd..4dc2d68e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1177,7 +1177,7 @@ } } - + - +