Skip to content

Commit 3534b6f

Browse files
committed
explainer/spec: Sync inputs must await each item
Fixes #9. See also #7.
1 parent c54fb6a commit 3534b6f

File tree

2 files changed

+78
-16
lines changed

2 files changed

+78
-16
lines changed

README.md

+14-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,20 @@ will also reject with that error.)
7272
`thisArg` is an optional value with which to call `mapfn`
7373
(or `undefined` by default).
7474

75-
Like `Array.from`, `Array.fromAsync` is a **generic factory method**.
75+
Like `for await`, when `Array.fromAsync` receives a **sync-iterable object**
76+
(and that object is not async iterable),
77+
then it creates a sync iterator for that object and adds its items to an array.
78+
When **any yielded item is a promise**, then that promise will **block** the iteration
79+
until it **resolves** to a value (in which case that value is what is added to the array)
80+
or until it **rejects** with an error (in which case
81+
the promise returned by `Array.fromAsync` itself will reject with that error).
82+
83+
Like `Array.from`, `Array.fromAsync` also works on non-iterable **array-like objects**
84+
(i.e., objects with a length property and indexed elements).
85+
As with sync-iterable objects, any element that is a promise must settle first,
86+
and the value to which it resolves (if any) will be what is added to the resulting array.
87+
88+
Also like `Array.from`, `Array.fromAsync` is a **generic factory method**.
7689
It does not require that its `this` value be the `Array` constructor,
7790
and it can be transferred to or inherited by any other constructors
7891
that may be called with a single numeric argument.

spec.html

+64-15
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ <h1><ins>Array.fromAsync ( _asyncItems_ [ , _mapfn_ [ , _thisArg_ ] ] )</ins></h
4848
1. Else,
4949
1. If IsCallable(_mapfn_) is *false*, throw a *TypeError* exception.
5050
1. Let _mapping_ be *true*.
51-
1. Let _usingAsyncOrSyncIterator_ be ? GetMethod(_asyncItems_, @@asyncIterator).
52-
1. If _usingAsyncOrSyncIterator_ is *undefined*, let _usingAsyncOrSyncIterator_ be ? GetMethod(_asyncItems_, @@iterator).
51+
1. Let _usingIterator_ be ? GetMethod(_asyncItems_, @@asyncIterator).
52+
1. If _usingIterator_ is *undefined*, then
53+
1. Set _usingIterator_ to ? GetMethod(_asyncItems_, @@iterator).
54+
1. If _usingIterator_ is *undefined*, set _usingIterator_ to CreateArrayIterator(_asyncItems_, ~value~).
55+
1. Set _usingIterator_ to CreateAsyncFromSyncIterator(_usingIterator_).
5356
1. If _usingAsyncOrSyncIterator_ is not *undefined*, then
5457
1. If IsConstructor(_C_) is *true*, then
5558
1. Let _A_ be ? Construct(_C_).
5659
1. Else,
5760
1. Let _A_ be ! ArrayCreate(0).
58-
1. Let _iteratorRecord_ be ? GetIterator(_asyncItems_, ~async~, _usingAsyncOrSyncIterator_).
61+
1. Let _iteratorRecord_ be ? GetIterator(_asyncItems_, ~async~, _usingIterator_).
5962
1. Let _k_ be 0.
6063
1. Repeat,
6164
1. If _k_ &ge; 2<sup>53</sup> - 1, then
@@ -77,30 +80,76 @@ <h1><ins>Array.fromAsync ( _asyncItems_ [ , _mapfn_ [ , _thisArg_ ] ] )</ins></h
7780
1. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
7881
1. If _defineStatus_ is an abrupt completion, return ? AsyncIteratorClose(_iteratorRecord_, _defineStatus_).
7982
1. Set _k_ to _k_ + 1.
80-
1. NOTE: _items_ is not an AsyncIterable or Iterable so assume it is an array-like object.
81-
1. Let _arrayLike_ be ! ToObject(_items_).
82-
1. Let _len_ be ? LengthOfArrayLike(_arrayLike_).
83-
1. If IsConstructor(_C_) is *true*, then
84-
1. Let _A_ be ? Construct(_C_, &laquo; 𝔽(_len_) &raquo;).
83+
1. Perform AsyncFunctionStart(promiseCapability, _fromAsyncClosure_).
84+
1. Return Completion { [[Type]]: ~return~, [[Value]]: _promiseCapability_.[[Promise]], [[Target]]: ~empty~ }.
85+
</emu-alg>
86+
<emu-note>
87+
<p>The `fromAsync` function is an intentionally generic factory method; it does not require that its *this* value be the Array constructor. Therefore it can be transferred to or inherited by any other constructors that may be called with a single numeric argument.</p>
88+
</emu-note>
89+
</emu-clause>
90+
</emu-clause>
91+
</emu-clause>
92+
93+
<emu-clause id="sec-typedarray-objects">
94+
<h1>TypedArray Objects</h1>
95+
96+
<emu-clause id="sec-properties-of-the-%typedarray%-intrinsic-object">
97+
<h1>Properties of the %TypedArray% Intrinsic Object</h1>
98+
99+
<emu-clause id="sec-%typedarray%.fromAsync">
100+
<h1><ins>%TypedArray%.fromAsync ( _source_ [ , _mapfn_ [ , _thisArg_ ] ] )</ins></h1>
101+
102+
<emu-note type=editor>
103+
<p>This section is a wholly new subsection of the <a
104+
href=https://tc39.es/ecma262/#sec-properties-of-the-%typedarray%-intrinsic-object>original
105+
Properties of the %TypedArray% Intrinsic Object clause</a>, to be inserted before the <a
106+
href=https://tc39.es/ecma262/#sec-%typedarray%.from>%TypedArray%.from
107+
clause</a>.</p>
108+
</emu-note>
109+
110+
<p>When the `fromAsync` method is called, the following steps are taken:</p>
111+
<emu-alg>
112+
1. Let _C_ be the *this* value.
113+
1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%).
114+
1. Let _fromAsyncClosure_ be a new Abstract Closure with no parameters that captures _C_ and _mapfn_ and performs the following steps when called:
115+
1. If IsConstructor(_C_) is *false*, throw a *TypeError* exception.
116+
1. If _mapfn_ is *undefined*, let _mapping_ be *false*.
85117
1. Else,
86-
1. Let _A_ be ? ArrayCreate(_len_).
118+
1. If IsCallable(_mapfn_) is *false*, throw a *TypeError* exception.
119+
1. Let _mapping_ be *true*.
120+
1. Let _usingIterator_ be ? GetMethod(_source_, @@iterator).
121+
1. If _usingIterator_ is not *undefined*, then
122+
1. Let _values_ be ? IterableToList(_source_, _usingIterator_).
123+
1. Let _len_ be the number of elements in _values_.
124+
1. Let _targetObj_ be ? TypedArrayCreate(_C_, &laquo; 𝔽(_len_) &raquo;).
125+
1. Let _k_ be 0.
126+
1. Repeat, while _k_ &lt; _len_,
127+
1. Let _Pk_ be ! ToString(𝔽(_k_)).
128+
1. Let _kValue_ be the first element of _values_ and remove that element from _values_.
129+
1. If _mapping_ is *true*, then
130+
1. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, &laquo; _kValue_, 𝔽(_k_) &raquo;).
131+
1. Else, let _mappedValue_ be _kValue_.
132+
1. Perform ? Set(_targetObj_, _Pk_, _mappedValue_, *true*).
133+
1. Set _k_ to _k_ + 1.
134+
1. Assert: _values_ is now an empty List.
135+
1. Return _targetObj_.
136+
1. NOTE: _source_ is not an Iterable so assume it is already an array-like object.
137+
1. Let _arrayLike_ be ! ToObject(_source_).
138+
1. Let _len_ be ? LengthOfArrayLike(_arrayLike_).
139+
1. Let _targetObj_ be ? TypedArrayCreate(_C_, &laquo; 𝔽(_len_) &raquo;).
87140
1. Let _k_ be 0.
88141
1. Repeat, while _k_ &lt; _len_,
89142
1. Let _Pk_ be ! ToString(𝔽(_k_)).
90143
1. Let _kValue_ be ? Get(_arrayLike_, _Pk_).
91144
1. If _mapping_ is *true*, then
92145
1. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, &laquo; _kValue_, 𝔽(_k_) &raquo;).
93146
1. Else, let _mappedValue_ be _kValue_.
94-
1. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
147+
1. Perform ? Set(_targetObj_, _Pk_, _mappedValue_, *true*).
95148
1. Set _k_ to _k_ + 1.
96-
1. Perform ? Set(_A_, *"length"*, 𝔽(_len_), *true*).
97-
1. Return _A_.
149+
1. Return _targetObj_.
98150
1. Perform AsyncFunctionStart(promiseCapability, _fromAsyncClosure_).
99151
1. Return Completion { [[Type]]: ~return~, [[Value]]: _promiseCapability_.[[Promise]], [[Target]]: ~empty~ }.
100152
</emu-alg>
101-
<emu-note>
102-
<p>The `fromAsync` function is an intentionally generic factory method; it does not require that its *this* value be the Array constructor. Therefore it can be transferred to or inherited by any other constructors that may be called with a single numeric argument.</p>
103-
</emu-note>
104153
</emu-clause>
105154
</emu-clause>
106155
</emu-clause>

0 commit comments

Comments
 (0)