Skip to content

explainer/spec: Sync inputs must await each item #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,20 @@ will also reject with that error.)
`thisArg` is an optional value with which to call `mapfn`
(or `undefined` by default).

Like `Array.from`, `Array.fromAsync` is a **generic factory method**.
Like `for await`, when `Array.fromAsync` receives a **sync-iterable object**
(and that object is not async iterable),
then it creates a sync iterator for that object and adds its items to an array.
When **any yielded item is a promise**, then that promise will **block** the iteration
until it **resolves** to a value (in which case that value is what is added to the array)
or until it **rejects** with an error (in which case
the promise returned by `Array.fromAsync` itself will reject with that error).

Like `Array.from`, `Array.fromAsync` also works on non-iterable **array-like objects**
(i.e., objects with a length property and indexed elements).
As with sync-iterable objects, any element that is a promise must settle first,
and the value to which it resolves (if any) will be what is added to the resulting array.

Also like `Array.from`, `Array.fromAsync` is a **generic factory method**.
It does not require that its `this` value be the `Array` constructor,
and it can be transferred to or inherited by any other constructors
that may be called with a single numeric argument.
Expand Down
68 changes: 27 additions & 41 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,53 +48,39 @@ <h1><ins>Array.fromAsync ( _asyncItems_ [ , _mapfn_ [ , _thisArg_ ] ] )</ins></h
1. Else,
1. If IsCallable(_mapfn_) is *false*, throw a *TypeError* exception.
1. Let _mapping_ be *true*.
1. Let _usingAsyncOrSyncIterator_ be ? GetMethod(_asyncItems_, @@asyncIterator).
1. If _usingAsyncOrSyncIterator_ is *undefined*, let _usingAsyncOrSyncIterator_ be ? GetMethod(_asyncItems_, @@iterator).
1. If _usingAsyncOrSyncIterator_ is not *undefined*, then
1. If IsConstructor(_C_) is *true*, then
1. Let _A_ be ? Construct(_C_).
1. Else,
1. Let _A_ be ! ArrayCreate(0).
1. Let _iteratorRecord_ be ? GetIterator(_asyncItems_, ~async~, _usingAsyncOrSyncIterator_).
1. Let _k_ be 0.
1. Repeat,
1. If _k_ &ge; 2<sup>53</sup> - 1, then
1. Let _error_ be ThrowCompletion(a newly created *TypeError* object).
1. Return ? AsyncIteratorClose(_iteratorRecord_, _error_).
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _next_ be ? Await(IteratorStep(_iteratorRecord_)).
1. If _next_ is *false*, then
1. Perform ? Set(_A_, *"length"*, 𝔽(_k_), *true*).
1. Return _A_.
1. Let _nextValue_ be ? IteratorValue(_next_).
1. If _mapping_ is *true*, then
1. Let _mappedValue_ be Call(_mapfn_, _thisArg_, &laquo; _nextValue_, 𝔽(_k_) &raquo;).
1. IfAbruptCloseAsyncIterator(_iteratorRecord_, _mappedValue_).
1. Let _mappedValue_ to Await(_mappedValue_).
1. IfAbruptCloseAsyncIterator(_iteratorRecord_, _mappedValue_).
1. Set _mappedValue_ to _mappedValue_.[[Value]].
1. Else, let _mappedValue_ be _nextValue_.
1. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
1. If _defineStatus_ is an abrupt completion, return ? AsyncIteratorClose(_iteratorRecord_, _defineStatus_).
1. Set _k_ to _k_ + 1.
1. NOTE: _items_ is not an AsyncIterable or Iterable so assume it is an array-like object.
1. Let _arrayLike_ be ! ToObject(_items_).
1. Let _len_ be ? LengthOfArrayLike(_arrayLike_).
1. Let _usingAsyncIterator_ be ? GetMethod(_asyncItems_, @@asyncIterator).
1. If _usingAsyncIterator_ is *undefined*,
1. Let _usingSyncIterator_ be ? GetMethod(_asyncItems_, @@iterator).
1. If _usingSyncIterator_ is *undefined*, set _usingSyncIterator_ to %Array.prototype.values%.
1. If IsConstructor(_C_) is *true*, then
1. Let _A_ be ? Construct(_C_, &laquo; 𝔽(_len_) &raquo;).
1. Let _A_ be ? Construct(_C_).
1. Else,
1. Let _A_ be ? ArrayCreate(_len_).
1. Let _A_ be ! ArrayCreate(0).
1. If _usingAsyncIterator_ is not *undefined*, then
1. Let _iteratorRecord_ be ? GetIterator(_asyncItems_, ~async~, _usingAsyncIterator_).
1. Else,
1. Let _iteratorRecord_ be ? CreateAsyncFromSyncIterator(GetIterator(_syncItems_, ~sync~, _usingSyncIterator_)).
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Repeat,
1. If _k_ &ge; 2<sup>53</sup> - 1, then
1. Let _error_ be ThrowCompletion(a newly created *TypeError* object).
1. Return ? AsyncIteratorClose(_iteratorRecord_, _error_).
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_arrayLike_, _Pk_).
1. Let _next_ be ? Await(IteratorStep(_iteratorRecord_)).
1. If _next_ is *false*, then
1. Perform ? Set(_A_, *"length"*, 𝔽(_k_), *true*).
1. Return _A_.
1. Let _nextValue_ be ? IteratorValue(_next_).
1. If _mapping_ is *true*, then
1. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, &laquo; _kValue_, 𝔽(_k_) &raquo;).
1. Else, let _mappedValue_ be _kValue_.
1. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
1. Let _mappedValue_ be Call(_mapfn_, _thisArg_, &laquo; _nextValue_, 𝔽(_k_) &raquo;).
1. IfAbruptCloseAsyncIterator(_iteratorRecord_, _mappedValue_).
1. Let _mappedValue_ to Await(_mappedValue_).
1. IfAbruptCloseAsyncIterator(_iteratorRecord_, _mappedValue_).
1. Set _mappedValue_ to _mappedValue_.[[Value]].
1. Else, let _mappedValue_ be _nextValue_.
1. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
1. If _defineStatus_ is an abrupt completion, return ? AsyncIteratorClose(_iteratorRecord_, _defineStatus_).
1. Set _k_ to _k_ + 1.
1. Perform ? Set(_A_, *"length"*, 𝔽(_len_), *true*).
1. Return _A_.
1. Perform AsyncFunctionStart(promiseCapability, _fromAsyncClosure_).
1. Return Completion { [[Type]]: ~return~, [[Value]]: _promiseCapability_.[[Promise]], [[Target]]: ~empty~ }.
</emu-alg>
Expand Down