You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Normative: Add machinery to track the incumbent settings object in HTML for Job callbacks (#2086)
In HTML, JS functions that are called asynchronously as part of jobs
(like Promise microtasks) are generally associated with a piece of state
called an incumbent settings object. The incumbent is stored at the time
when the callback is first passed to the API that is responsible for
scheduling the job (e.g. Promise.then), and restored when the callback
is called.
For symmetry, all WebIDL callbacks do this:
https://heycam.github.io/webidl/#idl-callback-interface
This PR adds the necessary host hook machinery to let HTML store and
restore the incumbent settings object. The default behavior is nop.
@@ -7793,6 +7793,91 @@ <h1>Jobs and Host Operations to Enqueue Jobs</h1>
7793
7793
7794
7794
<p>Particular kinds of Jobs have additional conformance requirements.</p>
7795
7795
7796
+
<emu-clause id="sec-jobcallback-records">
7797
+
<h1>JobCallback Records</h1>
7798
+
<p>A <dfn>JobCallback Record</dfn> is a Record value used to store a function object and a host-defined value. Function objects that are invoked via a Job enqueued by the host may have additional host-defined context. To propagate the state, Job Abstract Closures should not capture and call function objects directly. Instead, use HostMakeJobCallback and HostCallJobCallback.</p>
7799
+
<emu-note>
7800
+
<p>The WHATWG HTML specification (<a href="https://html.spec.whatwg.org/">https://html.spec.whatwg.org/</a>), for example, uses the host-defined value to propagate the incumbent settings object for Promise callbacks.</p>
7801
+
</emu-note>
7802
+
<p>JobCallback Records have the fields listed in <emu-xref href="#table-jobcallback-records"></emu-xref>.</p>
7803
+
<emu-table id="table-jobcallback-records" caption="JobCallback Record Fields">
<p>HostMakeJobCallback is a host-defined abstract operation that takes argument _callback_ (a function object).</p>
7847
+
<p>The implementation of HostMakeJobCallback must conform to the following requirements:</p>
7848
+
<ul>
7849
+
<li>It must always complete normally (i.e., not return an abrupt completion).</li>
7850
+
<li>It must always return a JobCallback Record whose [[Callback]] field is _callback_.</li>
7851
+
</ul>
7852
+
<p>The default implementation of HostMakeJobCallback performs the following steps when called:</p>
7853
+
<emu-alg>
7854
+
1. Assert: IsCallable(_callback_) is *true*.
7855
+
1. Return the JobCallback Record { [[Callback]]: _callback_, [[HostDefined]]: ~empty~ }.
7856
+
</emu-alg>
7857
+
<p>ECMAScript hosts that are not web browsers must use the default implementation of HostMakeJobCallback.</p>
7858
+
<emu-note>
7859
+
<p>This is called at the time that the callback is passed to the function that is responsible for its being eventually scheduled and run. For example, `promise.then(thenAction)` calls MakeJobCallback on `thenAction` at the time of invoking `Promise.prototype.then`, not at the time of scheduling the reaction Job.</p>
<p>HostCallJobCallback is a host-defined abstract operation that takes arguments _jobCallback_ (a JobCallback Record), _V_ (an ECMAScript language value), and _argumentsList_ (a List of ECMAScript language values).</p>
7866
+
<p>The implementation of HostCallJobCallback must conform to the following requirements:</p>
7867
+
<ul>
7868
+
<li>It must always perform and return the result of Call(_jobCallback_.[[Callback]], _V_, _argumentsList_).</li>
7869
+
</ul>
7870
+
<emu-note>
7871
+
<p>This requirement means that hosts cannot change the [[Call]] behaviour of function objects defined in this specification.</p>
7872
+
</emu-note>
7873
+
<p>The default implementation of HostCallJobCallback performs the following steps when called:</p>
7874
+
<emu-alg>
7875
+
1. Assert: IsCallable(_jobCallback_.[[Callback]]) is *true*.
<p>HostEnqueuePromiseJob is a host-defined abstract operation that schedules the Job Abstract Closure _job_ to be performed, at some future time. The Abstract Closures used with this algorithm are intended to be related to the handling of Promises, or otherwise, to be scheduled with equal priority to Promise handling operations.</p>
@@ -22797,7 +22882,7 @@ <h1>Script Records</h1>
22797
22882
[[HostDefined]]
22798
22883
</td>
22799
22884
<td>
22800
-
Any, default value is *undefined*.
22885
+
Any, default value is ~empty~.
22801
22886
</td>
22802
22887
<td>
22803
22888
Field reserved for use by host environments that need to associate additional information with a script.
The [[Type]] is used when [[Handler]] is *undefined* to allow for behaviour specific to the settlement type.
40666
+
The [[Type]] is used when [[Handler]] is ~empty~ to allow for behaviour specific to the settlement type.
40582
40667
</td>
40583
40668
</tr>
40584
40669
<tr>
40585
40670
<td>
40586
40671
[[Handler]]
40587
40672
</td>
40588
40673
<td>
40589
-
A function object or *undefined*.
40674
+
A JobCallback Record | ~empty~.
40590
40675
</td>
40591
40676
<td>
40592
-
The function that should be applied to the incoming value, and whose return value will govern what happens to the derived promise. If [[Handler]] is *undefined*, a function that depends on the value of [[Type]] will be used instead.
40677
+
The function that should be applied to the incoming value, and whose return value will govern what happens to the derived promise. If [[Handler]] is ~empty~, a function that depends on the value of [[Type]] will be used instead.
<p>The abstract operation TriggerPromiseReactions takes arguments _reactions_ (a collection of PromiseReaction Records) and _argument_. It enqueues a new Job for each record in _reactions_. Each such Job processes the [[Type]] and [[Handler]] of the PromiseReaction Record, and if the [[Handler]] is a function, calls it passing the given argument. If the [[Handler]] is *undefined*, the behaviour is determined by the [[Type]]. It performs the following steps when called:</p>
40827
+
<p>The abstract operation TriggerPromiseReactions takes arguments _reactions_ (a collection of PromiseReaction Records) and _argument_. It enqueues a new Job for each record in _reactions_. Each such Job processes the [[Type]] and [[Handler]] of the PromiseReaction Record, and if the [[Handler]] is not ~empty~, calls it passing the given argument. If the [[Handler]] is ~empty~, the behaviour is determined by the [[Type]]. It performs the following steps when called:</p>
40742
40828
<emu-alg>
40743
40829
1. For each _reaction_ in _reactions_, in original insertion order, do
40744
40830
1. Let _job_ be NewPromiseReactionJob(_reaction_, _argument_).
1. Let _status_ be Call(_promiseCapability_.[[Resolve]], *undefined*, « _handlerResult_.[[Value]] »).
40799
40885
1. Return Completion(_status_).
40800
40886
1. Let _handlerRealm_ be *null*.
40801
-
1. If _reaction_.[[Handler]] is not *undefined*, then
40802
-
1. Let _getHandlerRealmResult_ be GetFunctionRealm(_reaction_.[[Handler]]).
40887
+
1. If _reaction_.[[Handler]] is not ~empty~, then
40888
+
1. Let _getHandlerRealmResult_ be GetFunctionRealm(_reaction_.[[Handler]].[[Callback]]).
40803
40889
1. If _getHandlerRealmResult_ is a normal completion, then set _handlerRealm_ to _getHandlerRealmResult_.[[Value]].
40804
40890
1. Else, set _handlerRealm_ to the current Realm Record.
40805
40891
1. NOTE: _handlerRealm_ is never *null* unless the handler is *undefined*. When the handler is a revoked Proxy and no ECMAScript code runs, _handlerRealm_ is used to create error objects.
1. Let _job_ be a new Job Abstract Closure with no parameters that captures _promiseToResolve_, _thenable_, and _then_ and performs the following steps when called:
40815
40901
1. Let _resolvingFunctions_ be CreateResolvingFunctions(_promiseToResolve_).
40816
-
1. Let _thenCallResult_ be Call(_then_, _thenable_, « _resolvingFunctions_.[[Resolve]], _resolvingFunctions_.[[Reject]] »).
40902
+
1. Let _thenCallResult_ be HostCallJobCallback(_then_, _thenable_, « _resolvingFunctions_.[[Resolve]], _resolvingFunctions_.[[Reject]] »).
40817
40903
1. If _thenCallResult_ is an abrupt completion, then
40818
40904
1. Let _status_ be Call(_resolvingFunctions_.[[Reject]], *undefined*, « _thenCallResult_.[[Value]] »).
40819
40905
1. Return Completion(_status_).
40820
40906
1. Return Completion(_thenCallResult_).
40821
-
1. Let _getThenRealmResult_ be GetFunctionRealm(_then_).
40907
+
1. Let _getThenRealmResult_ be GetFunctionRealm(_then_.[[Callback]]).
40822
40908
1. If _getThenRealmResult_ is a normal completion, then let _thenRealm_ be _getThenRealmResult_.[[Value]].
40823
40909
1. Else, let _thenRealm_ be the current Realm Record.
40824
-
1. NOTE: _thenRealm_ is never *null*. When _then_ is a revoked Proxy and no code runs, _thenRealm_ is used to create error objects.
40910
+
1. NOTE: _thenRealm_ is never *null*. When _then_.[[Callback]] is a revoked Proxy and no code runs, _thenRealm_ is used to create error objects.
40825
40911
1. Return the Record { [[Job]]: _job_, [[Realm]]: _thenRealm_ }.
0 commit comments