Skip to content

Commit

Permalink
Change waitUntil behavior; use reference count approach for extension (
Browse files Browse the repository at this point in the history
…#1049)

(1) This removes the extendable event's extensions allowed flag and
introduces a reference count based approach instead of the
promise-copying-and-checking approach.

(2) This extends the opportunities of the lifetime extension by allowing
waitUntil() in the task queued by the reaction to the given promise.

Fixes #931 #935 #1039 #1050.
  • Loading branch information
jungkees authored Jan 11, 2017
1 parent 0feef08 commit 6c1f3fe
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 383 deletions.
57 changes: 27 additions & 30 deletions docs/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1289,25 +1289,33 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe

An {{ExtendableEvent}} object has an associated <dfn for="ExtendableEvent">extend lifetime promises</dfn> (an array of <a>promises</a>). It is initially an empty array.

An {{ExtendableEvent}} object has an associated <dfn id="extensions-allowed-flag">extensions allowed flag</dfn>. It is initially set.
An {{ExtendableEvent}} object has an associated <dfn for="ExtendableEvent">pending promises count</dfn> (the number of pending promises in the [=ExtendableEvent/extend lifetime promises=]). It is initially set to zero.

[=/Service workers=] have two <a>lifecycle events</a>, {{install!!event}} and {{activate!!event}}. [=/Service workers=] use the {{ExtendableEvent}} interface for {{activate!!event}} event and {{install!!event}} event.

<a href="#extensibility">Service worker extensions</a> that <a href="#extension-to-service-worker-global-scope">define event handlers</a> *may* also use or extend the {{ExtendableEvent}} interface.

Note: To extend the lifetime of a [=/service worker=], algorithms that <a>dispatch</a> events using the {{ExtendableEvent}} interface run [=Extend Service Worker Lifetime=] algorithm after <a>dispatching</a> the event. See <a>Handle Fetch</a>, <a>Handle Foreign Fetch</a>, and <a>Handle Functional Event</a>.

<section algorithm="wait-until-method">
<h4 id="wait-until-method">{{ExtendableEvent/waitUntil()|event.waitUntil(f)}}</h4>

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

<dfn method for="ExtendableEvent"><code>waitUntil(|f|)</code></dfn> method *must* run these steps:

1. If the <a>extensions allowed flag</a> is unset, then:
1. If the [=ExtendableEvent/pending promises count=] is zero and the [=dispatch flag=] is unset, then:
1. <a>Throw</a> an "{{InvalidStateError}}" exception.
1. Abort these steps.

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.

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 task queued by the reaction to the promise.

1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |f|, [=queue a task=], on |f|’s [=relevant settings object=]'s [=responsible event loop=] using the [=handle functional event task source=], to decrease the [=ExtendableEvent/pending promises count=] by one.

The user agent *should not* <a lt="terminate service worker">terminate</a> the [=/service worker=] associated with |event|'s <a>relevant settings object</a>'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.
</section>

[=/Service workers=] and <a href="#extensibility">extensions</a> that <a href="#extension-to-service-worker-global-scope">define event handlers</a> *may* define their own behaviors, allowing the [=ExtendableEvent/extend lifetime promises=] to suggest operation length, and the rejected state of any of the <a>promise</a> in [=ExtendableEvent/extend lifetime promises=] to suggest operation failure.
Expand Down Expand Up @@ -1450,6 +1458,11 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. <a>Throw</a> an "{{InvalidStateError}}" exception.
1. Abort these steps.
1. Add |r| to the <a>extend lifetime promises</a>.
1. Increase 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 task queued by the reaction to the promise.

1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a task=], on |r|’s [=relevant settings object=]'s [=responsible event loop=] using the [=handle fetch task source=], to decrease the [=ExtendableEvent/pending promises count=] by one.

Note: {{FetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called.

Expand Down Expand Up @@ -1561,6 +1574,14 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. <a>Throw</a> an "{{InvalidStateError}}" exception.
1. Abort these steps.
1. Add |r| to the <a>extend lifetime promises</a>.
1. Increase 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 task queued by the reaction to the promise.

1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a task=], on |r|’s [=relevant settings object=]'s [=responsible event loop=] using the [=handle fetch task source=], to decrease the [=ExtendableEvent/pending promises count=] by one.

Note: {{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called.

1. Set the <a>stop propagation flag</a> and <a>stop immediate propagation flag</a>.
1. Set the [=ForeignFetchEvent/respond-with entered flag=].
1. Set the [=ForeignFetchEvent/wait to respond flag=].
Expand Down Expand Up @@ -2678,9 +2699,8 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. Let |e| be the result of <a>creating an event</a> with {{InstallEvent}}.
1. Initialize |e|’s {{Event/type}} attribute to {{install!!event}}.
1. <a>Dispatch</a> |e| at |installingWorker|'s [=service worker/global object=].
1. Invoke [=Extend Service Worker Lifetime=] with |e|.
1. *WaitForAsynchronousExtensions*: Run the following substeps <a>in parallel</a>:
1. Wait until |e|'s <a>extensions allowed flag</a> is unset.
1. Wait until |e|'s [=ExtendableEvent/pending promises count=] is zero.
1. If the result of <a>waiting for all</a> of |e|'s <a>extend lifetime promises</a> rejected, set |installFailed| to true.

If |task| is discarded or the script has been aborted by the <a lt="Terminate Service Worker">termination</a> of |installingWorker|, set |installFailed| to true.
Expand Down Expand Up @@ -2744,8 +2764,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. Let |e| be the result of <a>creating an event</a> with {{ExtendableEvent}}.
1. Initialize |e|’s {{Event/type}} attribute to {{activate!!event}}.
1. <a>Dispatch</a> |e| at |activeWorker|'s [=service worker/global object=].
1. Invoke [=Extend Service Worker Lifetime=] with |e|.
1. *WaitForAsynchronousExtensions*: Wait, <a>in parallel</a>, until |e|'s <a>extensions allowed flag</a> is unset.
1. *WaitForAsynchronousExtensions*: Wait, <a>in parallel</a>, until |e|'s [=ExtendableEvent/pending promises count=] is zero.
1. Wait for |task| to have executed or been discarded, or the script to have been aborted by the <a lt="terminate service worker">termination</a> of |activeWorker|.
1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete.
1. Run the <a>Update Worker State</a> algorithm passing |registration|'s <a>active worker</a> and *activated* as the arguments.
Expand Down Expand Up @@ -2829,25 +2848,6 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. Abort the script currently running in |serviceWorker|.
</section>

<section algorithm>
<h3 id="extend-service-worker-lifetime-algorithm"><dfn>Extend Service Worker Lifetime</dfn></h3>

: Input
:: |event|, an {{ExtendableEvent}} object
: Output
:: None

1. If |event|'s <a>extend lifetime promises</a> is empty, unset |event|'s <a>extensions allowed flag</a> and abort these steps.
1. Let |extendLifetimePromises| be an empty array.
1. Run the following substeps <a>in parallel</a>:
1. *SetupPromiseArray*: Set |extendLifetimePromises| to a copy of |event|'s <a>extend lifetime promises</a>.
1. Wait until all the <a>promises</a> in |extendLifetimePromises| settle.
1. If the length of |extendLifetimePromises| does not equal the length of |event|'s <a>extend lifetime promises</a>, jump to the step labeled *SetupPromiseArray*.
1. Unset |event|'s <a>extensions allowed flag</a>.

The user agent *should not* <a lt="terminate service worker">terminate</a> the [=/service worker=] associated with |event|'s <a>relevant settings object</a>'s [=environment settings object/global object=] until |event|'s <a>extensions allowed flag</a> is unset. However, the user agent *may* impose a time limit to this lifetime extension.
</section>

<section algorithm>
<h3 id="on-fetch-request-algorithm"><dfn export>Handle Fetch</dfn></h3>

Expand Down Expand Up @@ -2926,7 +2926,6 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. If |request| is a <a>navigation request</a>, initialize |e|'s {{FetchEvent/targetClientId}} attribute to |request|'s [=request/target client id=], and to the empty string otherwise.
1. Let the {{FetchEvent/isReload}} attribute of |e| be initialized to <code>true</code> if |request|'s [=request/client=] is a <a>window client</a> and the event was dispatched with the user's intention for the page reload, and <code>false</code> otherwise.
1. <a>Dispatch</a> |e| at |activeWorker|'s [=service worker/global object=].
1. Invoke [=Extend Service Worker Lifetime=] with |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.
Expand Down Expand Up @@ -2990,7 +2989,6 @@ 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 <a lt="Unicode serialization of an origin">Unicode serialization</a> of |request|'s [=request/origin=].
1. <a>Dispatch</a> |e| at |activeWorker|'s [=service worker/global object=].
1. Invoke [=Extend Service Worker Lifetime=] with |e|.
1. If |e|'s [=ForeignFetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true.
1. If |e|'s <a>wait to respond flag</a> is set, wait until |e|'s <a>wait to respond flag</a> is unset.
1. Let |internalResponse| be |e|'s [=ForeignFetchEvent/potential response=].
Expand Down Expand Up @@ -3052,7 +3050,6 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe
1. Invoke <a>Run Service Worker</a> algorithm with |activeWorker| as the argument.
1. <a>Queue a task</a> |task| to run these substeps:
1. Invoke |callbackSteps| with |activeWorker|'s [=service worker/global object=] as its argument.
1. Invoke [=Extend Service Worker Lifetime=] with |event|.

The |task| *must* use |activeWorker|'s <a>event loop</a> and the <a>handle functional event task source</a>.

Expand Down
Loading

0 comments on commit 6c1f3fe

Please sign in to comment.