Skip to content

Commit d87d389

Browse files
authored
Allow async iterators to specify return algorithms
Closes #804. Notably this allows consumers to not worry about resolving their promise with the correct iterator result. This also fixes the "ongoing promise" to be a Promise or null, instead of a Promise or undefined, to better fit in the IDL value space.
1 parent 9d11c76 commit d87d389

File tree

1 file changed

+84
-5
lines changed

1 file changed

+84
-5
lines changed

index.bs

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4310,6 +4310,22 @@ iteration, or resolves with a tuple containing two elements:
43104310
1. a value of the first type given in the declaration;
43114311
1. a value of the second type given in the declaration.
43124312

4313+
The prose may also define an <dfn export>asynchronous iterator return</dfn> algorithm. This
4314+
algorithm receives the instance of the [=interface=] that is being iterated, the async iterator
4315+
itself, and a single argument value of type {{any}}. This algorithm is invoked in the case of
4316+
premature termination of the async iterator. It must return a {{Promise}}; if that promise
4317+
fulfills, its fulfillment value will be ignored, but if it rejects, that failure will be passed on
4318+
to users of the async iterator API.
4319+
4320+
<p class="note">In the ECMAScript binding, this algorithm allows customizing the behavior when the
4321+
async iterator's <code>return()</code> method is invoked. This most commonly occurs when a
4322+
<code>break</code> or <code>return</code> statement causes an exit from a
4323+
<code>for</code>-<code>await</code>-<code>of</code> loop.
4324+
4325+
<p class="note">We could add a similar hook for <code>throw()</code>. So far there has been no need,
4326+
but if you are creating an API that needs such capabilities, please
4327+
<a href="https://github.com/heycam/webidl/issues/new?title=Enhancement%20request%20for%20Async%20Iterables">file an issue</a>.
4328+
43134329
The prose may also define <dfn export>asynchronous iterator initialization steps</dfn>. These
43144330
receive the instance of the [=interface=] being iterated, as well as the newly-created
43154331
iterator object.
@@ -12504,7 +12520,7 @@ A [=default asynchronous iterator object=] has internal values:
1250412520
values are to be iterated,
1250512521
* its <dfn for="default asynchronous iterator object">kind</dfn>, which is the iteration kind,
1250612522
* its <dfn for="default asynchronous iterator object">ongoing promise</dfn>, which is a
12507-
{{Promise}} or undefined,
12523+
{{Promise}} or null,
1250812524
* its <dfn for="default asynchronous iterator object">is finished</dfn>, which is a boolean.
1250912525

1251012526
Note: [=Default asynchronous iterator objects=] do not have [=class strings=]; when
@@ -12571,8 +12587,8 @@ The \[[Prototype]] [=internal slot=] of an [=asynchronous iterator prototype obj
1257112587
[=default asynchronous iterator object/target=] and |object|.
1257212588
1. Let |fulfillSteps| be the following steps, given |next|:
1257312589
1. Set |object|'s [=default asynchronous iterator object/ongoing promise=] to
12574-
undefined.
12575-
1. If |next| is undefined, then:
12590+
null.
12591+
1. If |next| is <emu-val>undefined</emu-val>, then:
1257612592
1. Set |object|'s [=default asynchronous iterator object/is finished=] to true.
1257712593
1. Return [=!=] [$CreateIterResultObject$](<emu-val>undefined</emu-val>,
1257812594
<emu-val>true</emu-val>).
@@ -12585,7 +12601,7 @@ The \[[Prototype]] [=internal slot=] of an [=asynchronous iterator prototype obj
1258512601

1258612602
1. Let |promise| be |object|'s [=default asynchronous iterator object/ongoing promise=].
1258712603

12588-
1. If |promise| is not undefined, then:
12604+
1. If |promise| is not null, then:
1258912605
1. Let |afterOngoingPromiseCapability| be [=!=] [$NewPromiseCapability$]({{%Promise%}}).
1259012606
1. Let |onFulfilled| be [=!=] [$CreateBuiltinFunction$](|nextSteps|, « »).
1259112607
1. Perform [=!=] [$PerformPromiseThen$](|promise|, |onFulfilled|,
@@ -12600,7 +12616,70 @@ The \[[Prototype]] [=internal slot=] of an [=asynchronous iterator prototype obj
1260012616
1. Return |object|'s [=default asynchronous iterator object/ongoing promise=].
1260112617
</div>
1260212618

12603-
Issue: <code>return</code>; <code>throw</code> methods?
12619+
<div algorithm="to invoke the return property of asynchronous iterators">
12620+
12621+
If an [=asynchronous iterator return=] algorithm is defined for the [=inferface=], then the
12622+
[=asynchronous iterator prototype object=] must have a <code class="idl">return</code> data
12623+
property with attributes { \[[Writable]]: <emu-val>true</emu-val>,
12624+
\[[Enumerable]]: <emu-val>true</emu-val>, \[[Configurable]]: <emu-val>true</emu-val> }
12625+
and whose value is a [=built-in function object=], taking one argument |value|, that behaves as
12626+
follows:
12627+
12628+
1. Let |interface| be the [=interface=] for which the
12629+
[=asynchronous iterator prototype object=] exists.
12630+
12631+
1. Let |returnPromiseCapability| be [=!=] [$NewPromiseCapability$]({{%Promise%}}).
12632+
12633+
1. Let |object| be the result of calling [$ToObject$] on the
12634+
<emu-val>this</emu-val> value.
12635+
12636+
1. [$IfAbruptRejectPromise$](|object|, |returnPromiseCapability|).
12637+
12638+
1. If |object| [=is a platform object=], then [=perform a security check=], passing:
12639+
* the platform object |object|,
12640+
* the identifier "<code>return</code>", and
12641+
* the type "<code>method</code>".
12642+
12643+
If this threw an exception |e|, then:
12644+
1. Perform [=!=] [$Call$](|returnPromiseCapability|.\[[Reject]],
12645+
<emu-val>undefined</emu-val>, « |e| »).
12646+
1. Return |returnPromiseCapability|.\[[Promise]].
12647+
12648+
1. If |object| is not a [=default asynchronous iterator object=] for |interface|, then:
12649+
1. Let |error| be a new {{ECMAScript/TypeError}}.
12650+
1. Perform [=!=] [$Call$](|returnPromiseCapability|.\[[Reject]],
12651+
<emu-val>undefined</emu-val>, « |error| »).
12652+
1. Return |returnPromiseCapability|.\[[Promise]].
12653+
12654+
1. If |object|'s [=default asynchronous iterator object/ongoing promise=] is not null, then:
12655+
1. Let |error| be a new {{ECMAScript/TypeError}}.
12656+
1. Perform [=!=] [$Call$](|returnPromiseCapability|.\[[Reject]],
12657+
<emu-val>undefined</emu-val>, « |error| »).
12658+
1. Return |returnPromiseCapability|.\[[Promise]].
12659+
12660+
1. If |object|'s [=default asynchronous iterator object/is finished=] is true, then:
12661+
1. Let |result| be [=!=] [$CreateIterResultObject$](|value|,
12662+
<emu-val>true</emu-val>).
12663+
1. Perform [=!=] [$Call$](|returnPromiseCapability|.\[[Resolve]],
12664+
<emu-val>undefined</emu-val>, « |result| »).
12665+
1. Return |returnPromiseCapability|.\[[Promise]].
12666+
12667+
1. Set |object|'s [=default asynchronous iterator object/is finished=] to true.
12668+
12669+
1. Let |returnPromise| be the result of running the [=asynchronous iterator return=] algorithm
12670+
for |interface|, given |object|'s [=default asynchronous iterator object/target=],
12671+
|object|, and |value|.
12672+
12673+
1. Let |fulfillSteps| be the following steps:
12674+
1. Return [=!=] [$CreateIterResultObject$](|value|, <emu-val>true</emu-val>).
12675+
12676+
1. Let |onFulfilled| be [=!=] [$CreateBuiltinFunction$](|fulfillSteps|, « »).
12677+
12678+
1. Perform [=!=] [$PerformPromiseThen$](|returnPromise|, |onFulfilled|,
12679+
<emu-val>undefined</emu-val>, |returnPromiseCapability|).
12680+
12681+
1. Return |returnPromiseCapability|.\[[Promise]].
12682+
</div>
1260412683

1260512684
The [=class string=] of an [=asynchronous iterator prototype object=] for a given [=interface=] is
1260612685
the result of concatenating the [=identifier=] of the [=interface=] and the string

0 commit comments

Comments
 (0)