diff --git a/index.bs b/index.bs index c3c61084..f265b88f 100644 --- a/index.bs +++ b/index.bs @@ -19,6 +19,7 @@ spec: ecmascript; type: dfn; text: constructor text: realm spec: dom; type: dfn; text: element +spec: dom; type: dfn; for: /; text: document
@@ -34,6 +35,7 @@ urlPrefix: https://tc39.es/ecma262/; spec: ecmascript
     type: argument
         text: NewTarget; url: sec-built-in-function-objects
     type: abstract-op
+        text: CreateAsyncFromSyncIterator; url: sec-createasyncfromsynciterator
         text: Completion; url: sec-completion-record-specification-type
         text: IsInteger; url: sec-isinteger
         text: abs; url: eqn-abs
@@ -67,7 +69,9 @@ urlPrefix: https://tc39.es/ecma262/; spec: ecmascript
             text: internal slot
         text: own property; url: sec-own-property
         text: PromiseCapability; url: sec-promisecapability-records
+        text: Iterator Record; url: sec-iterator-records
         text: element size; url: table-the-typedarray-constructors
+        text: string object; url: sec-string-objects
         url: sec-ecmascript-language-types-bigint-type
             text: is a BigInt
             text: is not a BigInt
@@ -1688,6 +1692,7 @@ The type of the attribute, after resolving typedefs, must not be a
 [=nullable type|nullable=] or non-nullable version of any of the following types:
 
 *   a [=sequence type=]
+*   an [=async iterable type=]
 *   a [=dictionary type=]
 *   a [=record type=]
 *   a [=union type=]
@@ -3377,6 +3382,7 @@ the following algorithm returns true.
                 
interface-like
callback function
dictionary-like
+
async iterable
sequence-like
@@ -3392,6 +3398,7 @@ the following algorithm returns true. ● ● + ● boolean @@ -3405,6 +3412,7 @@ the following algorithm returns true. ● ● ● + ● numeric types @@ -3418,6 +3426,7 @@ the following algorithm returns true. ● ● ● + ● bigint @@ -3431,6 +3440,7 @@ the following algorithm returns true. ● ● ● + ● string types @@ -3443,6 +3453,7 @@ the following algorithm returns true. ● ● ● + (d) ● object @@ -3457,6 +3468,7 @@ the following algorithm returns true. + symbol @@ -3470,6 +3482,7 @@ the following algorithm returns true. ● ● ● + ● interface-like @@ -3483,6 +3496,7 @@ the following algorithm returns true. ● ● ● + ● callback function @@ -3496,6 +3510,7 @@ the following algorithm returns true. (c) ● + ● dictionary-like @@ -3509,6 +3524,21 @@ the following algorithm returns true. ● + ● + + async iterable + + + + + + + + + + + + sequence-like @@ -3521,6 +3551,7 @@ the following algorithm returns true. + @@ -3542,6 +3573,10 @@ the following algorithm returns true. then it is converted to a [=callback function=]. Otherwise, it is converted to a dictionary-like type. + 1. The types are distinguishable, but when converting from an ECMAScript value, + a [=string object=] is never converted to an [=async iterable type=] + (even if it has a {{%Symbol.iterator%}} method), if a [=string type=] + is also in the overload set or union.
@@ -4086,7 +4121,7 @@ The following extended attributes are applicable to [=iterable declarations=]:
-

Asynchronously iterable declarations

+

Asynchronously iterable declarations

An [=interface=] can be declared to be asynchronously iterable by using an asynchronously iterable declaration @@ -5693,6 +5728,7 @@ are known as object types. StringType Null identifier Null "sequence" "<" TypeWithExtendedAttributes ">" Null + "async iterable" "<" TypeWithExtendedAttributes ">" Null "object" Null "symbol" Null BufferRelatedType Null @@ -6185,6 +6221,34 @@ sequence is used. Any [=list=] can be implicitly treated as a sequence<|T|>, as long as it contains only [=list/items=] that are of type |T|. + + +

Async iterable types — async iterable<|T|>

+ +An async iterable type is a parameterized +type whose values are references to objects that can produce an asynchronously iterable, possibly infinite, +sequence of values of type |T|. + +Unlike [=sequences=], which are fixed-length lists where all values are known in advance, the asynchronously +iterable sequences created by async iterables are lazy. Their values may be produced asynchronously +only during iteration, and thus the values or length might not be known at the time the async +iterable is created. + +Async iterables are passed by reference in language bindings where they are represented by an object. +This means that passing an async iterable to a [=platform object=] will result in a reference to the +async iterable being kept by that object. Similarly, any async iterable returned from a platform +object will be a reference to the same object and modifications made to it will be visible to the +platform object. This is in contrast to sequences, which are always passed by value. + +Note: Async iterables cannot be constructed from IDL. If returned from an operation, or used as the +type of a dictionary member, the async iterable will have originated from the host environment and +have been turned into an IDL type via a language binding. Instead of returning an async iterable +from an IDL operation, the operation might want to return an [=interface=] that has an +[=asynchronously iterable declaration=]. + +Async iterables must not be used as the type of an [=attribute=] or [=constant=]. + +There is no way to represent an async iterable value in IDL.

Record types — record<|K|, |V|>

@@ -8120,6 +8184,162 @@ JavaScript Array values. +

Async iterables — async iterable<|T|>

+ +In the JavaScript binding, IDL [=async iterable type|async iterable=] values are represented by +a [=struct=] with the following [=struct/items=]: + +* object, a JavaScript value +* method, a JavaScript value +* type, either "sync" or "async" + + +
+ A JavaScript value |V| is [=converted to an IDL value|converted=] + to an IDL async iterable<T> value as follows: + + 1. If |V| [=is not an Object=], then + [=JavaScript/throw=] a {{TypeError}}. + 1. Let |method| be [=?=] GetMethod(obj, {{%Symbol.asyncIterator%}}). + 1. If |method| is undefined: + 1. Set |syncMethod| to [=?=] GetMethod(obj, {{%Symbol.iterator%}}). + 1. If |syncMethod| is undefined, [=JavaScript/throw=] a {{TypeError}}. + 1. Return an IDL [=async iterable=] value with [=JS async iterable/object=] set to |V|, + [=JS async iterable/method=] set to |syncMethod|, and [=JS async iterable/type=] set to + "sync". + 1. Return an IDL [=async iterable=] value with [=JS async iterable/object=] set to |V|, + [=JS async iterable/method=] set to |method|, and [=JS async iterable/type=] set to + "async". +
+ +
+ An IDL async iterable<T> value |V| is + [=converted to a JavaScript value|converted=] to a JavaScript object as follows: + + 1. Return |V|'s [=JS async iterable/object=]. +
+ +
Iterating async iterators
+ +An [=async iterable=] is not directly iterated over. Instead, it is first opened to create +an [=async iterator=]. The [=async iterator=] can be asynchronously iterated over to produce values. + +Async iterators are [=structs=] with the following [=struct/items=]: +* underlying record, an [=Iterator Record=] +* type parameter, an IDL type representing the type of values produced by the async iterator + +
+ + To open an + async iterable<T> |iterable|: + + 1. Let |iterator| be [=?=] GetIteratorFromMethod(|iterable|'s + [=JS async iterable/object=], |iterable|'s [=JS async iterable/method=]). + 1. If |iterable|'s [=JS async iterable/type=] is "sync", set |iterator| to + CreateAsyncFromSyncIterator(|iterator|). + 1. Return an [=async iterator=] value with [=JS async iterator/underlying record=] set to |iterator| and + [=JS async iterator/type parameter=] set to |T|. + +
+ + + +
+ + To get the next value of an + [=async iterator=] |iterator|: + + 1. Let |nextResult| be + IteratorNext(|iterator|'s [=JS async iterator/underlying record=]). + 1. If |nextResult| is an [=abrupt completion=], return [=a promise rejected with=] + |nextResult|.\[[Value]]. + 1. Let |nextPromise| be [=a promise resolved with=] |nextResult|.\[[Value]]. + 1. Return the result of [=reacting=] to |nextPromise| with the following fulfillment + steps, given |iterResult|: + 1. If |iterResult| [=is not an Object=], [=JavaScript/throw=] a + {{TypeError}}. + 1. Let |done| be [=?=] IteratorComplete(|iterResult|). + 1. If |done| is true: + 1. Return [=end of iteration=]. + 1. Otherwise: + 1. Let |V| be [=?=] IteratorValue(|iterResult|). + 1. Let |value| be the result of [=converted to an IDL value|converting=] |V| to an IDL + value of type |iterator|'s [=JS async iterator/type parameter=]. + 1. Return |value|. + +
+ +
+ + To close an + async iterator<T> |iterator|, + with an ECMAScript value |reason|: + + 1. Let |iteratorRecord| be |iterator|'s [=JS async iterator/underlying record=]. + 1. Let |iteratorObj| be |iteratorRecord|.\[[Iterator]]. + 1. Let |returnMethod| be GetMethod(|iteratorObj|, "return"). + 1. If |returnMethod| is an [=abrupt completion=], return [=a promise rejected with=] + |returnMethod|.\[[Value]]. + 1. If |returnMethod| is undefined, return [=a promise resolved with=] + {{undefined}}. + 1. Let |returnResult| be Call(|returnMethod|.\[[Value]], |iteratorObj|, « |reason| »). + 1. If |returnResult| is an [=abrupt completion=], return [=a promise rejected with=] + |returnResult|.\[[Value]]. + 1. Let |returnPromise| be [=a promise resolved with=] |returnResult|.\[[Value]]. + 1. Return the result of [=reacting=] to |returnPromise| with the following fulfillment steps, + given |returnPromiseResult|: + 1. If |returnPromiseResult| [=is not an Object=], [=JavaScript/throw=] a + {{TypeError}}. + 1. Return {{undefined}}. + +
+ +
+ + concatN is an [=operation=] that returns a promise that will be fulfilled with the + concatenation of all the strings yielded by the async iterable passed to it. It stops + concatenating and closes the iterator once the async iterable has yielded maxN + strings. + +
+        interface I {
+          Promise<DOMString> concatN(async iterable<DOMString> strings, unsigned long maxN);
+        };
+    
+ +
+ + The concatN(|iterable|, |maxN|) method steps are: + + 1. Let |promise| be [=a new promise=]. + 1. Let |result| be the empty string. + 1. Let |n| be 0. + 1. Let |iterator| be the result of opening |iterable|. + 1. Let |step| be a sequence of steps that will be used to process the async iterable: + 1. Let |next| be the result of getting the next value of |iterator|. + 1. [=React=] to |next|: + - If |next| was fulfilled with value |v|: + 1. If |v| is [=end of iteration=], [=resolve=] |promise| with |result|. + 1. Set |result| to the result of concatenating |result| and |v|. + 1. Set |n| to |n| + 1. + 1. If |n| is |maxN|, then: + 1. Let |finish| be the result of closing + |iterator| with reason {{undefined}}. + 1. [=React=] to |finish|: + - If |finish| was fulfilled, [=resolve=] |promise| with |result|. + - If |finish| was rejected with reason |r|, [=reject=] |promise| with |r|. + 1. Otherwise: + 1. Call |step|. + - If |next| was rejected with reason |r|, [=reject=] |promise| with |r|. + 1. Call |step|. + 1. Return |promise|. + +
+
+ + + +

Records — record<|K|, |V|>

IDL [=record=]<|K|, |V|> values are represented by @@ -8686,6 +8906,18 @@ that correspond to the union's [=member types=]. 1. If |types| includes {{object}}, then return the IDL value that is a reference to the object |V|. 1. If |V| [=is an Object=], then: + 1. If |types| includes an [=async iterable type=], then + 1. If |types| does not include a [=string type=] or |V| does not have a \[[StringData]] [=/internal slot=], then + 1. Let |asyncMethod| be [=?=] GetMethod(|V|, {{%Symbol.asyncIterator%}}). + 1. If |asyncMethod| is not undefined, + return an IDL [=async iterable=] value with [=JS async iterable/object=] + set to |V|, [=JS async iterable/method=] set to |syncMethod|, and + [=JS async iterable/type=] set to "async". + 1. Let |syncMethod| be [=?=] GetMethod(|V|, {{%Symbol.iterator%}}). + 1. If |syncMethod| is not undefined, + return an IDL [=async iterable=] value with [=JS async iterable/object=] + set to |V|, [=JS async iterable/method=] set to |syncMethod|, and + [=JS async iterable/type=] set to "sync". 1. If |types| includes a [=sequence type=], then 1. Let |method| be [=?=] GetMethod(|V|, {{%Symbol.iterator%}}). 1. If |method| is not undefined, @@ -11257,14 +11489,40 @@ Note: The HTML Standard defines how a security check is performed. [[!HTML]] then remove from |S| all other entries. + 1. Otherwise: if |V| [=is an Object=] and + there is an entry in |S| that has one of the + following types at position |i| of its type list, + * an [=async iterable type=] + * a [=nullable type|nullable=] version of any of the above types + * an [=annotated type=] whose [=annotated types/inner type=] is one of the above types + * a [=union type=], [=nullable type|nullable=] union type, or [=annotated type|annotated=] union type + that has one of the above types in its [=flattened member types=] + + and the following are not all true, + * |V| has a \[[StringData]] [=/internal slot=] + * |S| has one of the following types at position |i| of its type list, + * a [=string type=] + * a [=nullable type|nullable=] version of a [=string type=] + * an [=annotated type=] whose [=annotated types/inner type=] is a [=string type=] + * a [=union type=], [=nullable type|nullable=] union type, or [=annotated type|annotated=] union type + that has one of the above types in its [=flattened member types=] + + and after performing the following steps, + + 1. Let |method| be [=?=] GetMethod(|V|, {{%Symbol.asyncIterator%}}). + 1. If |method| is undefined, then set |method| to [=?=] GetMethod(|V|, {{%Symbol.iterator%}}). + + |method| is not undefined, then remove from |S| all + other entries. + 1. Otherwise: if |V| [=is an Object=] and there is an entry in |S| that has one of the following types at position |i| of its type list, * a [=sequence type=] - * a [=nullable type|nullable=] [=sequence type=] - * an [=annotated type=] whose [=annotated types/inner type=] is a [=sequence type=] + * a [=nullable type|nullable=] version of any of the above types + * an [=annotated type=] whose [=annotated types/inner type=] is one of the above types * a [=union type=], [=nullable type|nullable=] union type, or [=annotated type|annotated=] union type - that has a [=sequence type=] in its [=flattened member types=] + that has one of the above types in its [=flattened member types=] and after performing the following steps, @@ -11424,11 +11682,11 @@ Note: The HTML Standard defines how a security check is performed. [[!HTML]] Generally, the inspection of the value at the distinguishing argument index does not have any side effects, and the only side effects in the overload resolution algorithm are the result of converting the JavaScript values to IDL values. - (An exception exists when one of the overloads has a [=sequence type=] or [=frozen array type=] - at the distinguishing argument index. - In this case, we attempt to get the {{%Symbol.iterator%}} property to determine the appropriate - overload, and perform the conversion of the distinguishing argument separately before continuing - with the next step.) + (An exception exists when one of the overloads has an [=async iterable type=], [=sequence type=] + or [=frozen array type=] at the distinguishing argument index. + In this case, we attempt to get the {{%Symbol.asyncIterator%}} / {{%Symbol.iterator%}} property + to determine the appropriate overload, and perform the conversion of the distinguishing argument + separately before continuing with the next step.) At this point, we have determined which overload to use. We now convert the remaining arguments, from the distinguishing argument onwards,