├── .gitignore
├── .github
└── workflows
│ ├── build.yml
│ └── deploy.yml
├── package.json
├── DETAILS.md
├── README.md
├── proposal-iterator-helpers-biblio.json
└── spec.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
4 | .DS_Store
5 | Desktop.ini
6 | ._*
7 | Thumbs.db
8 | .Spotlight-V100
9 | .Trashes
10 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build spec
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: 16
18 | - run: npm ci
19 | - run: npm run build
20 | - run: npm run check-format
21 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy gh-pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | deploy:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: 16
17 | - run: npm ci
18 | - run: npm run build
19 | - uses: JamesIves/github-pages-deploy-action@v4.3.3
20 | with:
21 | branch: gh-pages
22 | folder: dist
23 | clean: true
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "build": "mkdir -p dist && ecmarkup --lint-spec --strict --load-biblio @tc39/ecma262-biblio --load-biblio ./proposal-iterator-helpers-biblio.json --verbose --js-out dist/ecmarkup.js --css-out dist/ecmarkup.css spec.html dist/index.html",
5 | "format": "emu-format --write spec.html",
6 | "check-format": "emu-format --check spec.html"
7 | },
8 | "devDependencies": {
9 | "@tc39/ecma262-biblio": "2.1.2407",
10 | "ecmarkup": "^15.0.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/DETAILS.md:
--------------------------------------------------------------------------------
1 | # Details
2 |
3 | There are number of decisions which could be made differently. This document attempts to catalog them along with the rationales for the choices currently made.
4 |
5 | ## Getting an iterator record from `this`
6 |
7 | The added methods on `%IteratorPrototype%` assume that `this` is an iterator,
8 | and therefore use a new `GetIteratorDirect` method to acquire an iterator
9 | record. This means that code like `Iterator.syncPrototype.map.call([1, 2, 3], ...)`
10 | will not work.
11 |
12 | ## Passing the protocol
13 |
14 | All added methods attempt to pass the values and calls they receive to whatever
15 | iterator they are wrapping. For example, `it.map(fn).next(5)` will call
16 | `it.next(5)` instead of `it.next()`. Additionally, calls like
17 | `it.map(fn).return()` will call upwards as well, to `it.return()`.
18 |
19 | ## Interface constraints
20 |
21 | - The interface used to expose these methods must not clash with existing APIs.
22 | For example: `Array.prototype.map` or `Map.prototype.forEach` denying access
23 | to the interface.
24 | - It must work with everywhere an iteration can occur.
25 | For example: `%GeneratorFunction%.prototype.map` will not work because the
26 | interface has to be obtained from an explicit function call.
27 | `%GeneratorFunction%.prototype` has no symbolic API to get the iterator.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Async Iterator Helpers
2 |
3 | A proposal for several interfaces that will help with general usage and
4 | consumption of async iterators in ECMAScript.
5 |
6 | This proposal was split out from [proposal-iterator-helpers](https://github.com/tc39/proposal-iterator-helpers) to resolve design questions related to concurrency (see below), which are not relevant to sync helpers. Many design questions (including choice of methods) were discussed and decided in that respository, and its readme should be read first.
7 |
8 | ## Status
9 |
10 | Authors: Gus Caplan, Michael Ficarra, Adam Vandolder, Jason Orendorff, Kevin Gibbons
11 |
12 | Champions: Michael Ficarra, Kevin Gibbons
13 |
14 | This proposal is at Stage 2 of [The TC39 Process](https://tc39.es/process-document/).
15 |
16 | **This proposal is in the process of being revised.** The core set of helpers and their high-level API is unlikely to change, but the underlying specification mechanism will likely be radically revised.
17 |
18 | This proposal contains the following methods:
19 |
20 | - `Iterator.prototype.toAsync`
21 | - `AsyncIterator.from`
22 | - `AsyncIterator.prototype`
23 | - `.map`
24 | - `.filter`
25 | - `.take`
26 | - `.drop`
27 | - `.flatMap`
28 | - `.reduce`
29 | - `.toArray`
30 | - `.forEach`
31 | - `.some`
32 | - `.every`
33 | - `.find`
34 |
35 | See [proposal-iterator-helpers](https://github.com/tc39/proposal-iterator-helpers) for motivation and additional high-level descriptions for these methods.
36 |
37 | ## Concurrency
38 |
39 | In the iterator-producing methods (`.map`, `.filter`, `.take`, `.drop`, and `.flatMap`), async helpers have the opportunity to support _concurrency_. For example, in the following code:
40 |
41 | ```js
42 | x = asyncIteratorOfUrls
43 | .map(u => fetch(u))
44 |
45 | await Promise.all([
46 | x.next(),
47 | x.next(),
48 | ])
49 | ```
50 |
51 | there could be two calls to `fetch` running at once. For this to work, the helpers have to be explicitly designed to support this. The original design of this proposal instead implemented the helpers as essentially async generators, which buffer calls to `.next` rather than allowing multiple calls to have simultaneous effects.
52 |
53 | This proposal is being revised to support at least the above use case. The exact details of what that looks like for each helper are not yet decided.
54 |
55 | ## How can I access the new intrinsics?
56 |
57 | This proposal introduces two new intrisic objects, in addition to the two added in the sync proposal. They can be accessed as follows:
58 |
59 | ```js
60 | const AsyncIteratorHelperPrototype = Object.getPrototypeOf(AsyncIterator.from([]).take(0));
61 | const WrapForValidAsyncIteratorPrototype = Object.getPrototypeOf(AsyncIterator.from({ async next(){} }));
62 | ```
63 |
--------------------------------------------------------------------------------
/proposal-iterator-helpers-biblio.json:
--------------------------------------------------------------------------------
1 | {"location":"https://tc39.es/proposal-iterator-helpers","entries":[{"type":"table","id":"table-7","number":1,"caption":"Table 1: Well-Known Intrinsic Objects"},{"type":"clause","id":"sec-well-known-intrinsic-objects","aoid":null,"title":"Well-Known Intrinsic Objects","titleHTML":"Well-Known Intrinsic Objects","number":"1"},{"type":"op","aoid":"GetIteratorDirect","refId":"sec-getiteratordirect","kind":"abstract operation","signature":{"parameters":[{"name":"_obj_","type":{"kind":"opaque","type":"an ECMAScript language value"}}],"optionalParameters":[],"return":{"kind":"completion","completionType":"mixed","typeOfValueIfNormal":{"kind":"opaque","type":"an Iterator Record"}}},"effects":["user-code"]},{"type":"clause","id":"sec-getiteratordirect","aoid":"GetIteratorDirect","title":"GetIteratorDirect ( obj )","titleHTML":"GetIteratorDirect ( obj )","number":"2.1.1"},{"type":"op","aoid":"GetIteratorFlattenable","refId":"sec-getiteratorflattenable","kind":"abstract operation","signature":{"parameters":[{"name":"_obj_","type":{"kind":"opaque","type":"an ECMAScript language value"}},{"name":"_hint_","type":{"kind":"union","types":[{"kind":"opaque","type":"~sync~"},{"kind":"opaque","type":"~async~"}]}}],"optionalParameters":[],"return":{"kind":"completion","completionType":"mixed","typeOfValueIfNormal":{"kind":"opaque","type":"an Iterator Record"}}},"effects":["user-code"]},{"type":"clause","id":"sec-getiteratorflattenable","aoid":"GetIteratorFlattenable","title":"GetIteratorFlattenable ( obj, hint )","titleHTML":"GetIteratorFlattenable ( obj, hint )","number":"2.1.2"},{"type":"clause","id":"sec-operations-on-iterator-objects","aoid":null,"title":"Operations on Iterator Objects","titleHTML":"Operations on Iterator Objects","number":"2.1"},{"type":"clause","id":"sec-abstract-operations","aoid":null,"title":"Abstract Operations","titleHTML":"Abstract Operations","number":"2"},{"type":"term","term":"Iterator","refId":"sec-iterator-constructor"},{"type":"term","term":"%Iterator%","refId":"sec-iterator-constructor"},{"type":"clause","id":"sec-iterator","aoid":null,"title":"Iterator ( )","titleHTML":"Iterator ( )","number":"3.1.1.1.1"},{"type":"clause","id":"sec-iterator-constructor","aoid":null,"title":"The Iterator Constructor","titleHTML":"The Iterator Constructor","number":"3.1.1.1"},{"type":"clause","id":"sec-iterator.prototype","aoid":null,"title":"Iterator.prototype","titleHTML":"Iterator.prototype","number":"3.1.1.2.1"},{"type":"term","term":"%WrapForValidIteratorPrototype%","refId":"sec-wrapforvaliditeratorprototype-object"},{"type":"clause","id":"sec-wrapforvaliditeratorprototype.next","aoid":null,"title":"%WrapForValidIteratorPrototype%.next ( )","titleHTML":"%WrapForValidIteratorPrototype%.next ( )","number":"3.1.1.2.2.1.1"},{"type":"clause","id":"sec-wrapforvaliditeratorprototype.return","aoid":null,"title":"%WrapForValidIteratorPrototype%.return ( )","titleHTML":"%WrapForValidIteratorPrototype%.return ( )","number":"3.1.1.2.2.1.2"},{"type":"clause","id":"sec-wrapforvaliditeratorprototype-object","aoid":null,"title":"The %WrapForValidIteratorPrototype% Object","titleHTML":"The %WrapForValidIteratorPrototype% Object","number":"3.1.1.2.2.1"},{"type":"clause","id":"sec-iterator.from","aoid":null,"title":"Iterator.from ( O )","titleHTML":"Iterator.from ( O )","number":"3.1.1.2.2"},{"type":"clause","id":"sec-properties-of-the-iterator-constructor","aoid":null,"title":"Properties of the Iterator Constructor","titleHTML":"Properties of the Iterator Constructor","number":"3.1.1.2"},{"type":"clause","id":"sec-iterator-objects","aoid":null,"title":"Iterator Objects","titleHTML":"Iterator Objects","number":"3.1.1"},{"type":"term","term":"%IteratorHelperPrototype%","refId":"sec-%iteratorhelperprototype%-object"},{"type":"clause","id":"sec-%iteratorhelperprototype%.next","aoid":null,"title":"%IteratorHelperPrototype%.next ( )","titleHTML":"%IteratorHelperPrototype%.next ( )","number":"3.1.2.1.1"},{"type":"clause","id":"sec-%iteratorhelperprototype%.return","aoid":null,"title":"%IteratorHelperPrototype%.return ( )","titleHTML":"%IteratorHelperPrototype%.return ( )","number":"3.1.2.1.2"},{"type":"clause","id":"sec-%iteratorhelperprototype%-@@tostringtag","aoid":null,"title":"%IteratorHelperPrototype% [ @@toStringTag ]","titleHTML":"%IteratorHelperPrototype% [ @@toStringTag ]","number":"3.1.2.1.3"},{"type":"clause","id":"sec-%iteratorhelperprototype%-object","aoid":null,"title":"The %IteratorHelperPrototype% Object","titleHTML":"The %IteratorHelperPrototype% Object","number":"3.1.2.1"},{"type":"clause","id":"sec-iterator-helper-objects","aoid":null,"title":"Iterator Helper Objects","titleHTML":"Iterator Helper Objects","number":"3.1.2"},{"type":"term","term":"Iterator prototype object","refId":"sec-iteratorprototype"},{"type":"term","term":"%Iterator.prototype%","refId":"sec-iteratorprototype"},{"type":"clause","id":"sec-iteratorprototype.constructor","aoid":null,"title":"Iterator.prototype.constructor","titleHTML":"Iterator.prototype.constructor","number":"3.1.3.1"},{"type":"clause","id":"sec-iteratorprototype.map","aoid":null,"title":"Iterator.prototype.map ( mapper )","titleHTML":"Iterator.prototype.map ( mapper )","number":"3.1.3.2"},{"type":"clause","id":"sec-iteratorprototype.filter","aoid":null,"title":"Iterator.prototype.filter ( predicate )","titleHTML":"Iterator.prototype.filter ( predicate )","number":"3.1.3.3"},{"type":"clause","id":"sec-iteratorprototype.take","aoid":null,"title":"Iterator.prototype.take ( limit )","titleHTML":"Iterator.prototype.take ( limit )","number":"3.1.3.4"},{"type":"clause","id":"sec-iteratorprototype.drop","aoid":null,"title":"Iterator.prototype.drop ( limit )","titleHTML":"Iterator.prototype.drop ( limit )","number":"3.1.3.5"},{"type":"clause","id":"sec-iteratorprototype.flatmap","aoid":null,"title":"Iterator.prototype.flatMap ( mapper )","titleHTML":"Iterator.prototype.flatMap ( mapper )","number":"3.1.3.6"},{"type":"clause","id":"sec-iteratorprototype.reduce","aoid":null,"title":"Iterator.prototype.reduce ( reducer [ , initialValue ] )","titleHTML":"Iterator.prototype.reduce ( reducer [ , initialValue ] )","number":"3.1.3.7"},{"type":"clause","id":"sec-iteratorprototype.toarray","aoid":null,"title":"Iterator.prototype.toArray ( )","titleHTML":"Iterator.prototype.toArray ( )","number":"3.1.3.8"},{"type":"clause","id":"sec-iteratorprototype.foreach","aoid":null,"title":"Iterator.prototype.forEach ( fn )","titleHTML":"Iterator.prototype.forEach ( fn )","number":"3.1.3.9"},{"type":"clause","id":"sec-iteratorprototype.some","aoid":null,"title":"Iterator.prototype.some ( predicate )","titleHTML":"Iterator.prototype.some ( predicate )","number":"3.1.3.10"},{"type":"clause","id":"sec-iteratorprototype.every","aoid":null,"title":"Iterator.prototype.every ( predicate )","titleHTML":"Iterator.prototype.every ( predicate )","number":"3.1.3.11"},{"type":"clause","id":"sec-iteratorprototype.find","aoid":null,"title":"Iterator.prototype.find ( predicate )","titleHTML":"Iterator.prototype.find ( predicate )","number":"3.1.3.12"},{"type":"clause","id":"sec-iteratorprototype-@@tostringtag","aoid":null,"title":"Iterator.prototype [ @@toStringTag ]","titleHTML":"Iterator.prototype [ @@toStringTag ]","number":"3.1.3.13"},{"type":"clause","id":"sec-iteratorprototype","aoid":null,"title":"Iterator.prototype","titleHTML":"Iterator.prototype","number":"3.1.3"},{"type":"clause","id":"sec-iteration","aoid":null,"title":"Iteration","titleHTML":"Iteration","number":"3.1"},{"type":"clause","id":"sec-control-abstraction-objects","aoid":null,"title":"Control Abstraction Objects","titleHTML":"Control Abstraction Objects","number":"3"}]}
--------------------------------------------------------------------------------
/spec.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | title: Async Iterator Helpers
5 | status: proposal
6 | stage: 2
7 | location: https://tc39.es/proposal-async-iterator-helpers
8 | copyright: false
9 | contributors: Gus Caplan, Michael Ficarra, Kevin Gibbons
10 |
11 |
45 |
46 |
62 |
63 |
64 | Well-Known Intrinsic Objects
65 |
66 |
67 |
68 |
69 | |
70 | Intrinsic Name
71 | |
72 |
73 | Global Name
74 | |
75 |
76 | ECMAScript Language Association
77 | |
78 |
79 |
80 | |
81 | %AsyncIterator%
82 | |
83 |
84 | `AsyncIterator`
85 | |
86 |
87 | The `AsyncIterator` constructor ()
88 | |
89 |
90 |
91 | |
92 | %AsyncIteratorPrototype%
93 | |
94 |
95 | `AsyncIterator.prototype`
96 | |
97 |
98 | An object that all standard built-in async iterator objects indirectly inherit from
99 | The initial value of the *"prototype"* data property of %AsyncIterator%; i.e., %AsyncIterator.prototype%
100 | |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Control Abstraction Objects
108 |
109 |
110 | Iteration
111 |
112 |
113 | Iterator Abstract Operations
114 |
115 |
116 | IfAbruptCloseAsyncIterator ( _value_, _iteratorRecord_ )
117 | IfAbruptCloseAsyncIterator is a shorthand for a sequence of algorithm steps that use an Iterator Record. An algorithm step of the form:
118 |
119 | 1. IfAbruptCloseAsyncIterator(_value_, _iteratorRecord_).
120 |
121 | means the same thing as:
122 |
123 | 1. If _value_ is an abrupt completion, then
124 | 1. Perform ? AsyncIteratorClose(_iteratorRecord_, _value_).
125 | 1. Return _value_.
126 | 1. Else if _value_ is a Completion Record, set _value_ to _value_.[[Value]].
127 |
128 |
129 |
130 |
131 |
132 | AwaitNonPrimitive (
133 | _value_: an ECMAScript language value,
134 | ): either a normal completion containing an ECMAScript language value or a throw completion
135 |
136 |
138 |
139 | 1. If _value_ is an Object, return ? Await(_value_).
140 | 1. Else, return _value_.
141 |
142 |
143 |
144 |
145 |
146 | AsyncIterator Objects
147 |
148 |
149 | The AsyncIterator Constructor
150 | The AsyncIterator constructor:
151 |
152 | - is %AsyncIterator%.
153 | - is the initial value of the *"AsyncIterator"* property of the global object.
154 | - is designed to be subclassable. It may be used as the value of an *extends* clause of a class definition.
155 |
156 |
157 |
158 | AsyncIterator ( )
159 | When the `AsyncIterator` function is called, the following steps are taken:
160 |
161 | 1. If NewTarget is *undefined* or the active function object, throw a *TypeError* exception.
162 | 1. Return ? OrdinaryCreateFromConstructor(NewTarget, *"%AsyncIterator.prototype%"*).
163 |
164 |
165 |
166 |
167 |
168 | Properties of the AsyncIterator Constructor
169 |
170 |
171 | AsyncIterator.prototype
172 | The initial value of AsyncIterator.prototype is %AsyncIterator.prototype%.
173 | This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
174 |
175 |
176 |
177 | AsyncIterator.from ( _O_ )
178 |
179 | 1. If _O_ is a String, set _O_ to ! ToObject(_O_).
180 | 1. Let _iteratorRecord_ be ? GetIteratorFlattenable(_O_, ~async~).
181 | 1. Let _hasInstance_ be ? OrdinaryHasInstance(%AsyncIterator%, _iteratorRecord_.[[Iterator]]).
182 | 1. If _hasInstance_ is *true*, then
183 | 1. Return _iteratorRecord_.[[Iterator]].
184 | 1. Let _wrapper_ be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »).
185 | 1. Set _wrapper_.[[AsyncIterated]] to _iteratorRecord_.
186 | 1. Return _wrapper_.
187 |
188 |
189 |
190 | The %WrapForValidAsyncIteratorPrototype% Object
191 | The %WrapForValidAsyncIteratorPrototype% object:
192 |
193 |
194 | - is an ordinary object.
195 | - has a [[Prototype]] internal slot whose value is %AsyncIterator.prototype%.
196 | - has the following properties:
197 |
198 |
199 |
200 | %WrapForValidAsyncIteratorPrototype%.next ( )
201 |
202 | 1. Let _O_ be *this* value.
203 | 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
204 | 1. Let _check_ be Completion(RequireInternalSlot(_O_, [[AsyncIterated]])).
205 | 1. IfAbruptRejectPromise(_check_, _promiseCapability_).
206 | 1. Let _result_ be Completion(IteratorNext(_O_.[[AsyncIterated]])).
207 | 1. IfAbruptRejectPromise(_result_, _promiseCapability_).
208 | 1. Return ? PromiseResolve(%Promise%, _result_).
209 |
210 |
211 |
212 |
213 | %WrapForValidAsyncIteratorPrototype%.return ( )
214 |
215 | 1. Let _O_ be *this* value.
216 | 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
217 | 1. Let _check_ be Completion(RequireInternalSlot(_O_, [[AsyncIterated]])).
218 | 1. IfAbruptRejectPromise(_check_, _promiseCapability_).
219 | 1. Let _iterator_ be _O_.[[AsyncIterated]].[[Iterator]].
220 | 1. Assert: _iterator_ is an Object.
221 | 1. Let _returnMethod_ be Completion(GetMethod(_iterator_, *"return"*)).
222 | 1. IfAbruptRejectPromise(_returnMethod_, _promiseCapability_).
223 | 1. If _returnMethod_ is *undefined*, then
224 | 1. Return ! PromiseResolve(%Promise%, CreateIterResultObject(*undefined*, *true*)).
225 | 1. Let _result_ be Completion(Call(_returnMethod_, _iterator_)).
226 | 1. IfAbruptRejectPromise(_result_, _promiseCapability_).
227 | 1. Return ? PromiseResolve(%Promise%, _result_).
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 | Async Iterator Helper Objects
237 | An Async Iterator Helper object is an ordinary object that represents a lazy transformation of some specific source async iterator object. There is not a named constructor for Async Iterator Helper objects. Instead, Async Iterator Helper objects are created by calling certain methods of AsyncIterator instance objects.
238 |
239 |
240 | The %AsyncIteratorHelperPrototype% Object
241 | The %AsyncIteratorHelperPrototype% object:
242 |
243 | - has properties that are inherited by all Async Iterator Helper Objects.
244 | - is an ordinary object.
245 | - has a [[Prototype]] internal slot whose value is %AsyncIterator.prototype%.
246 | - has the following properties:
247 |
248 |
249 |
250 | %AsyncIteratorHelperPrototype%.next ( )
251 |
252 | 1. Return AsyncGeneratorNext(*this* value, *"Async Iterator Helper"*, *undefined*).
253 |
254 |
255 |
256 |
257 | %AsyncIteratorHelperPrototype%.return ( )
258 |
259 | 1. Return AsyncGeneratorReturn(*this* value, *"Async Iterator Helper"*, *undefined*).
260 |
261 |
262 |
263 |
264 | %AsyncIteratorHelperPrototype% [ @@toStringTag ]
265 | The initial value of the @@toStringTag property is the String value *"Async Iterator Helper"*.
266 | This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
267 |
268 |
269 |
270 |
271 |
272 | Iterator.prototype
273 |
274 |
275 | Iterator.prototype.toAsync ( )
276 | This method performs the following steps when called:
277 |
278 | 1. Let _syncIteratorRecord_ be ? GetIteratorDirect(*this* value).
279 | 1. Let _asyncIteratorRecord_ be CreateAsyncFromSyncIterator(_syncIteratorRecord_).
280 | 1. Let _wrapper_ be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »).
281 | 1. Set _wrapper_.[[AsyncIterated]] to _asyncIteratorRecord_.
282 | 1. Return _wrapper_.
283 |
284 |
285 |
286 |
287 |
288 | AsyncIterator.prototype
289 | The AsyncIterator prototype object:
290 |
291 | - is %AsyncIterator.prototype%.
292 | - has a [[Prototype]] internal slot whose value is %Object.prototype%.
293 | - is an ordinary object.
294 |
295 |
296 |
297 | AsyncIterator.prototype.constructor
298 | The initial value of AsyncIterator.prototype.constructor is %AsyncIterator%.
299 |
300 |
301 |
302 | AsyncIterator.prototype.map ( _mapper_ )
303 | This method performs the following steps when called:
304 |
305 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
306 | 1. If IsCallable(_mapper_) is *false*, throw a *TypeError* exception.
307 | 1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and _mapper_ and performs the following steps when called:
308 | 1. Let _counter_ be 0.
309 | 1. Repeat,
310 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
311 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
312 | 1. Let _value_ be ? IteratorValue(_next_).
313 | 1. Let _mapped_ be Completion(Call(_mapper_, *undefined*, « _value_, 𝔽(_counter_) »)).
314 | 1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
315 | 1. Set _mapped_ to Completion(AwaitNonPrimitive(_mapped_)).
316 | 1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
317 | 1. Let _completion_ be Completion(Yield(_mapped_)).
318 | 1. IfAbruptCloseAsyncIterator(_completion_, _iterated_).
319 | 1. Set _counter_ to _counter_ + 1.
320 | 1. Return CreateAsyncIteratorFromClosure(_closure_, *"Async Iterator Helper"*, %AsyncIteratorHelperPrototype%).
321 |
322 |
323 |
324 |
325 | AsyncIterator.prototype.filter ( _predicate_ )
326 | This method performs the following steps when called:
327 |
328 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
329 | 1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
330 | 1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and _predicate_ and performs the following steps when called:
331 | 1. Let _counter_ be 0.
332 | 1. Repeat,
333 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
334 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
335 | 1. Let _value_ be ? IteratorValue(_next_).
336 | 1. Let _selected_ be Completion(Call(_predicate_, *undefined*, « _value_, 𝔽(_counter_) »)).
337 | 1. IfAbruptCloseAsyncIterator(_selected_, _iterated_).
338 | 1. Set _selected_ to Completion(AwaitNonPrimitive(_selected_)).
339 | 1. IfAbruptCloseAsyncIterator(_selected_, _iterated_).
340 | 1. If ToBoolean(_selected_) is *true*, then
341 | 1. Let _completion_ be Completion(Yield(_value_)).
342 | 1. IfAbruptCloseAsyncIterator(_completion_, _iterated_).
343 | 1. Set _counter_ to _counter_ + 1.
344 | 1. Return CreateAsyncIteratorFromClosure(_closure_, *"Async Iterator Helper"*, %AsyncIteratorHelperPrototype%).
345 |
346 |
347 |
348 |
349 | AsyncIterator.prototype.take ( _limit_ )
350 | This method performs the following steps when called:
351 |
352 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
353 | 1. Let _numLimit_ be ? ToNumber(_limit_).
354 | 1. If _numLimit_ is *NaN*, throw a *RangeError* exception.
355 | 1. Let _integerLimit_ be ! ToIntegerOrInfinity(_numLimit_).
356 | 1. If _integerLimit_ < 0, throw a *RangeError* exception.
357 | 1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and _integerLimit_ and performs the following steps when called:
358 | 1. Let _remaining_ be _integerLimit_.
359 | 1. Repeat,
360 | 1. If _remaining_ is 0, then
361 | 1. Return ? AsyncIteratorClose(_iterated_, NormalCompletion(*undefined*)).
362 | 1. If _remaining_ is not +∞, then
363 | 1. Set _remaining_ to _remaining_ - 1.
364 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
365 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
366 | 1. Let _completion_ be Completion(Yield(? IteratorValue(_next_))).
367 | 1. IfAbruptCloseAsyncIterator(_completion_, _iterated_).
368 | 1. Return CreateAsyncIteratorFromClosure(_closure_, *"Async Iterator Helper"*, %AsyncIteratorHelperPrototype%).
369 |
370 |
371 |
372 |
373 | AsyncIterator.prototype.drop ( _limit_ )
374 | This method performs the following steps when called:
375 |
376 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
377 | 1. Let _numLimit_ be ? ToNumber(_limit_).
378 | 1. If _numLimit_ is *NaN*, throw a *RangeError* exception.
379 | 1. Let _integerLimit_ be ! ToIntegerOrInfinity(_numLimit_).
380 | 1. If _integerLimit_ < 0, throw a *RangeError* exception.
381 | 1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and _integerLimit_ and performs the following steps when called:
382 | 1. Let _remaining_ be _integerLimit_.
383 | 1. Repeat, while _remaining_ > 0,
384 | 1. If _remaining_ is not +∞, then
385 | 1. Set _remaining_ to _remaining_ - 1.
386 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
387 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
388 | 1. Repeat,
389 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
390 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
391 | 1. Let _completion_ be Completion(Yield(? IteratorValue(_next_))).
392 | 1. IfAbruptCloseAsyncIterator(_completion_, _iterated_).
393 | 1. Return CreateAsyncIteratorFromClosure(_closure_, *"Async Iterator Helper"*, %AsyncIteratorHelperPrototype%).
394 |
395 |
396 |
397 |
398 | AsyncIterator.prototype.flatMap ( _mapper_ )
399 | This method performs the following steps when called:
400 |
401 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
402 | 1. If IsCallable(_mapper_) is *false*, throw a *TypeError* exception.
403 | 1. Let _closure_ be a new Abstract Closure with no parameters that captures _iterated_ and _mapper_ and performs the following steps when called:
404 | 1. Let _counter_ be 0.
405 | 1. Repeat,
406 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
407 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
408 | 1. Let _value_ be ? IteratorValue(_next_).
409 | 1. Let _mapped_ be Completion(Call(_mapper_, *undefined*, « _value_, 𝔽(_counter_) »)).
410 | 1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
411 | 1. Set _mapped_ to Completion(AwaitNonPrimitive(_mapped_)).
412 | 1. IfAbruptCloseAsyncIterator(_mapped_, _iterated_).
413 | 1. Let _innerIterator_ be Completion(GetIteratorFlattenable(_mapped_, ~async~)).
414 | 1. IfAbruptCloseAsyncIterator(_innerIterator_, _iterated_).
415 | 1. Let _innerAlive_ be *true*.
416 | 1. Repeat, while _innerAlive_ is *true*,
417 | 1. Let _innerNextPromise_ be Completion(IteratorNext(_innerIterator_)).
418 | 1. IfAbruptCloseAsyncIterator(_innerNextPromise_, _iterated_).
419 | 1. Let _innerNext_ be Completion(Await(_innerNextPromise_)).
420 | 1. IfAbruptCloseAsyncIterator(_innerNext_, _iterated_).
421 | 1. Let _innerComplete_ be Completion(IteratorComplete(_innerNext_)).
422 | 1. IfAbruptCloseAsyncIterator(_innerComplete_, _iterated_).
423 | 1. If _innerComplete_ is *true*, then
424 | 1. Set _innerAlive_ to *false*.
425 | 1. Else,
426 | 1. Let _innerValue_ be Completion(IteratorValue(_innerNext_)).
427 | 1. IfAbruptCloseAsyncIterator(_innerValue_, _iterated_).
428 | 1. [id="step-async-iterator-flatmap-yield"] Let _completion_ be Completion(Yield(_innerValue_)).
429 | 1. If _completion_ is a return completion, then
430 | 1. Let _backupCompletion_ be Completion(IteratorClose(_innerIterator_, _completion_)).
431 | 1. IfAbruptCloseIterator(_backupCompletion_, _iterated_).
432 | 1. Return ? IteratorClose(_completion_, _iterated_).
433 | 1. Else if _completion_ is a throw completion, then
434 | 1. Assert: Awaiting _innerValue_ during the Yield on step threw.
435 | 1. Return ? IteratorClose(_completion_, _iterated_).
436 | 1. Set _counter_ to _counter_ + 1.
437 | 1. Return CreateAsyncIteratorFromClosure(_closure_, *"Async Iterator Helper"*, %AsyncIteratorHelperPrototype%).
438 |
439 |
440 |
441 |
442 | AsyncIterator.prototype.reduce ( _reducer_ [ , _initialValue_ ] )
443 | This async method performs the following steps when called:
444 |
445 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
446 | 1. If IsCallable(_reducer_) is *false*, throw a *TypeError* exception.
447 | 1. If _initialValue_ is not present, then
448 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
449 | 1. If ? IteratorComplete(_next_) is *true*, throw a *TypeError* exception.
450 | 1. Let _accumulator_ be ? IteratorValue(_next_).
451 | 1. Let _counter_ be 1.
452 | 1. Else,
453 | 1. Let _accumulator_ be _initialValue_.
454 | 1. Let _counter_ be 0.
455 | 1. Repeat,
456 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
457 | 1. If ? IteratorComplete(_next_) is *true*, return _accumulator_.
458 | 1. Let _value_ be ? IteratorValue(_next_).
459 | 1. Let _result_ be Completion(Call(_reducer_, *undefined*, « _accumulator_, _value_, 𝔽(_counter_) »)).
460 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
461 | 1. Set _result_ to Completion(AwaitNonPrimitive(_result_)).
462 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
463 | 1. Set _accumulator_ to _result_.
464 | 1. Set _counter_ to _counter_ + 1.
465 |
466 |
467 |
468 |
469 | AsyncIterator.prototype.toArray ( )
470 | This async method performs the following steps when called:
471 |
472 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
473 | 1. Let _items_ be a new empty List.
474 | 1. Repeat,
475 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
476 | 1. If ? IteratorComplete(_next_) is *true*, return CreateArrayFromList(_items_).
477 | 1. Let _value_ be ? IteratorValue(_next_).
478 | 1. Append _value_ to _items_.
479 |
480 |
481 |
482 |
483 | AsyncIterator.prototype.forEach ( _fn_ )
484 | This async method performs the following steps when called:
485 |
486 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
487 | 1. If IsCallable(_fn_) is *false*, throw a *TypeError* exception.
488 | 1. Let _counter_ be 0.
489 | 1. Repeat,
490 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
491 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
492 | 1. Let _value_ be ? IteratorValue(_next_).
493 | 1. Let _r_ be Completion(Call(_fn_, *undefined*, « _value_, 𝔽(_counter_) »)).
494 | 1. IfAbruptCloseAsyncIterator(_r_, _iterated_).
495 | 1. Set _r_ to Completion(AwaitNonPrimitive(r)).
496 | 1. IfAbruptCloseAsyncIterator(_r_, _iterated_).
497 | 1. Set _counter_ to _counter_ + 1.
498 |
499 |
500 |
501 |
502 | AsyncIterator.prototype.some ( _predicate_ )
503 | This async method performs the following steps when called:
504 |
505 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
506 | 1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
507 | 1. Let _counter_ be 0.
508 | 1. Repeat,
509 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
510 | 1. If ? IteratorComplete(_next_) is *true*, return *false*.
511 | 1. Let _value_ be ? IteratorValue(_next_).
512 | 1. Let _result_ be Completion(Call(_predicate_, *undefined*, « _value_, 𝔽(_counter_) »)).
513 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
514 | 1. Set _result_ to Completion(AwaitNonPrimitive(_result_)).
515 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
516 | 1. If ToBoolean(_result_) is *true*, return ? AsyncIteratorClose(_iterated_, NormalCompletion(*true*)).
517 | 1. Set _counter_ to _counter_ + 1.
518 |
519 |
520 |
521 |
522 | AsyncIterator.prototype.every ( _predicate_ )
523 | This async method performs the following steps when called:
524 |
525 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
526 | 1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
527 | 1. Let _counter_ be 0.
528 | 1. Repeat,
529 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
530 | 1. If ? IteratorComplete(_next_) is *true*, return *true*.
531 | 1. Let _value_ be ? IteratorValue(_next_).
532 | 1. Let _result_ be Completion(Call(_predicate_, *undefined*, « _value_, 𝔽(_counter_) »)).
533 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
534 | 1. Set _result_ to Completion(AwaitNonPrimitive(_result_)).
535 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
536 | 1. If ToBoolean(_result_) is *false*, return ? AsyncIteratorClose(_iterated_, NormalCompletion(*false*)).
537 | 1. Set _counter_ to _counter_ + 1.
538 |
539 |
540 |
541 |
542 | AsyncIterator.prototype.find ( _predicate_ )
543 | This async method performs the following steps when called:
544 |
545 | 1. Let _iterated_ be ? GetIteratorDirect(*this* value).
546 | 1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
547 | 1. Let _counter_ be 0.
548 | 1. Repeat,
549 | 1. Let _next_ be ? Await(? IteratorNext(_iterated_)).
550 | 1. If ? IteratorComplete(_next_) is *true*, return *undefined*.
551 | 1. Let _value_ be ? IteratorValue(_next_).
552 | 1. Let _result_ be Completion(Call(_predicate_, *undefined*, « _value_, 𝔽(_counter_) »)).
553 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
554 | 1. Set _result_ to Completion(AwaitNonPrimitive(_result_)).
555 | 1. IfAbruptCloseAsyncIterator(_result_, _iterated_).
556 | 1. If ToBoolean(_result_) is *true*, return ? AsyncIteratorClose(_iterated_, NormalCompletion(_value_)).
557 | 1. Set _counter_ to _counter_ + 1.
558 |
559 |
560 |
561 |
562 | AsyncIterator.prototype [ @@toStringTag ]
563 | The initial value of the @@toStringTag property is the String value *"Async Iterator"*.
564 |
565 | Unlike the @@toStringTag on most built-in classes, for web-compatibility reasons this property must be writable.
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 | New AsyncGenerator AOs
574 | These factor out functionality from AsyncGenerator.prototype.next and AsyncGenerator.prototype.return and should be used in those methods when this proposal lands in the main specification.
575 |
576 |
577 |
578 | AsyncGeneratorNext (
579 | _generator_: unknown,
580 | _brand_: unknown,
581 | _value_: an ECMAScript language value,
582 | ): an ECMAScript language value
583 |
584 |
586 |
587 | 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
588 | 1. Let _result_ be Completion(AsyncGeneratorValidate(_generator_, _brand_)).
589 | 1. IfAbruptRejectPromise(_result_, _promiseCapability_).
590 | 1. Let _state_ be _generator_.[[AsyncGeneratorState]].
591 | 1. If _state_ is ~completed~, then
592 | 1. Let _iteratorResult_ be CreateIterResultObject(*undefined*, *true*).
593 | 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, « _iteratorResult_ »).
594 | 1. Return _promiseCapability_.[[Promise]].
595 | 1. Let _completion_ be NormalCompletion(_value_).
596 | 1. Perform AsyncGeneratorEnqueue(_generator_, _completion_, _promiseCapability_).
597 | 1. If _state_ is either ~suspendedStart~ or ~suspendedYield~, then
598 | 1. Perform AsyncGeneratorResume(_generator_, _completion_).
599 | 1. Else,
600 | 1. Assert: _state_ is either ~executing~ or ~awaiting-return~.
601 | 1. Return _promiseCapability_.[[Promise]].
602 |
603 |
604 |
605 |
606 |
607 | AsyncGeneratorReturn (
608 | _generator_: unknown,
609 | _brand_: unknown,
610 | _value_: an ECMAScript language value,
611 | ): an ECMAScript language value
612 |
613 |
615 |
616 | 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
617 | 1. Let _result_ be Completion(AsyncGeneratorValidate(_generator_, _brand_)).
618 | 1. IfAbruptRejectPromise(_result_, _promiseCapability_).
619 | 1. Let _completion_ be Completion Record { [[Type]]: ~return~, [[Value]]: _value_, [[Target]]: ~empty~ }.
620 | 1. Perform AsyncGeneratorEnqueue(_generator_, _completion_, _promiseCapability_).
621 | 1. Let _state_ be _generator_.[[AsyncGeneratorState]].
622 | 1. If _state_ is either ~suspendedStart~ or ~completed~, then
623 | 1. Set _generator_.[[AsyncGeneratorState]] to ~awaiting-return~.
624 | 1. Perform ! AsyncGeneratorAwaitReturn(_generator_).
625 | 1. Else if _state_ is ~suspendedYield~, then
626 | 1. Perform AsyncGeneratorResume(_generator_, _completion_).
627 | 1. Else,
628 | 1. Assert: _state_ is either ~executing~ or ~awaiting-return~.
629 | 1. Return _promiseCapability_.[[Promise]].
630 |
631 |
632 |
633 |
--------------------------------------------------------------------------------