    title: ES Array.fromAsync (2022)
    status: proposal
    stage: 1
    location: https://github.com/js-choi/proposal-array-async-from
    copyright: false
    contributors: J. S. Choi

# Introduction

This is the formal specification for a proposed `Array.fromAsync` factory method in JavaScript. It modifies the original ECMAScript specification with several new or revised clauses. See the proposal's explainer for the proposal's background, motivation, and usage examples.

# Control Abstraction Objects

# Iteration

# Iterator Abstract Operations

# IfAbruptCloseAsyncIterator ( _value_, _iteratorRecord_ )

IfAbruptCloseAsyncIterator is a shorthand for a sequence of algorithm steps that use an Iterator Record. An algorithm step of the form:

1. IfAbruptCloseAsyncIterator(_value_, _iteratorRecord_).

means the same thing as:

1. If _value_ is an abrupt completion, then 1. Perform ? AsyncIteratorClose(_iteratorRecord_, _value_). 1. Return _value_. 1. Else if _value_ is a Completion Record, set _value_ to _value_.[[Value]].

# AsyncFunction Objects

# Async Functions Abstract Operations

# AsyncBlockStart ( _promiseCapability_: a PromiseCapability Record, _asyncBody_: a Parse Node or an Abstract Closure with no parameters, _asyncContext_: an execution context, )

1. Assert: _promiseCapability_ is a PromiseCapability Record. 1. Let _runningContext_ be the running execution context. 1. [fence-effects="user-code"] Set the code evaluation state of _asyncContext_ such that when evaluation is resumed for that execution context the following steps will be performed: 1. If _asyncBody_ is a Parse Node, then 1. Let _result_ be the result of evaluating _asyncBody_. 1. Else, 1. Assert: _asyncBody_ is an Abstract Closure with no parameters. 1. Let _result_ be _asyncBody_(). 1. Let _result_ be the result of evaluating _asyncBody_. 1. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done. 1. Remove _asyncContext_ from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. 1. If _result_.[[Type]] is ~normal~, then 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, « *undefined* »). 1. Else if _result_.[[Type]] is ~return~, then 1. Perform ! Call(_promiseCapability_.[[Resolve]], *undefined*, « _result_.[[Value]] »). 1. Else, 1. Assert: _result_.[[Type]] is ~throw~. 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « _result_.[[Value]] »). 1. [id="step-asyncblockstart-return-undefined"] Return. 1. Push _asyncContext_ onto the execution context stack; _asyncContext_ is now the running execution context. 1. Resume the suspended evaluation of _asyncContext_. Let _result_ be the value returned by the resumed computation. 1. Assert: When we return here, _asyncContext_ has already been removed from the execution context stack and _runningContext_ is the currently running execution context. 1. Assert: _result_ is a normal completion with a value of *undefined*. The possible sources of completion values are Await or, if the async function doesn't await anything, step above. 1. Return.

# Indexed Collections

# Array Objects

# Properties of the Array Constructor

# Array.fromAsync ( _asyncItems_ [ , _mapfn_ [ , _thisArg_ ] ] )

This section is a wholly new subsection of the original Properties of the Array Constructor clause, to be inserted before the Array.from clause.

When the `fromAsync` method is called, the following steps are taken:

1. Let _C_ be the *this* value. 1. Let _promiseCapability_ be ! NewPromiseCapability(%Promise%). 1. Let _fromAsyncClosure_ be a new Abstract Closure with no parameters that captures _C_, _mapfn_, and _thisArg_ and performs the following steps when called: 1. If _mapfn_ is *undefined*, let _mapping_ be *false*. 1. Else, 1. If IsCallable(_mapfn_) is *false*, throw a *TypeError* exception. 1. Let _mapping_ be *true*. 1. Let _usingAsyncIterator_ be ? GetMethod(_asyncItems_, @@asyncIterator). 1. If _usingAsyncIterator_ is *undefined*, then 1. Let _usingSyncIterator_ be ? GetMethod(_asyncItems_, @@iterator). 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 *undefined*. 1. If _usingAsyncIterator_ is not *undefined*, then 1. Set _iteratorRecord_ to ? GetIterator(_asyncItems_, ~async~, _usingAsyncIterator_). 1. Else if _usingSyncIterator_ is not *undefined*, then 1. Set _iteratorRecord_ to ? CreateAsyncFromSyncIterator(GetIterator(_asyncItems_, ~sync~, _usingSyncIterator_)). 1. If _iteratorRecord_ is not *undefined*, then 1. Let _k_ be 0. 1. Repeat, 1. If _k_ ≥ 253 - 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 Completion Record { [[Type]]: ~return~, [[Value]]: _A_, [[Target]]: ~empty~ }. 1. Let _nextValue_ be ? IteratorValue(_next_). 1. If _mapping_ is *true*, then 1. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »). 1. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_). 1. Set _mappedValue_ to Await(_mappedValue_). 1. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_). 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. Else, 1. NOTE: _asyncItems_ is neither an AsyncIterable nor an Iterable so assume it is an array-like object. 1. Let _arrayLike_ be ! ToObject(_asyncItems_). 1. Let _len_ be ? LengthOfArrayLike(_arrayLike_). 1. If IsConstructor(_C_) is *true*, then 1. Let _A_ be ? Construct(_C_, « 𝔽(_len_) »). 1. Else, 1. Let _A_ be ? ArrayCreate(_len_). 1. Let _k_ be 0. 1. Repeat, while _k_ < _len_, 1. Let _Pk_ be ! ToString(𝔽(_k_)). 1. Let _kValue_ be ? Get(_arrayLike_, _Pk_). 1. Let _kValue_ be ? Await(_kValue_). 1. If _mapping_ is *true*, then 1. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, « _kValue_, 𝔽(_k_) »). 1. Let _mappedValue_ be ? Await(_mappedValue_). 1. Else, let _mappedValue_ be _kValue_. 1. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_). 1. Set _k_ to _k_ + 1. 1. Perform ? Set(_A_, *"length"*, 𝔽(_len_), *true*). 1. Return Completion Record { [[Type]]: ~return~, [[Value]]: _A_, [[Target]]: ~empty~ }. 1. Perform AsyncFunctionStart(_promiseCapability_, _fromAsyncClosure_). 1. Return _promiseCapability_.[[Promise]].

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.