Stage 3 (Conditional on Editor Review) Draft / May 15, 2025

ES Array.fromAsync

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.

This proposal depends on the pull request tc39/ecma262#2942: “support built-in async functions”.

1 Abstract Operations

1.1 Operations on Iterator Objects

1.1.1 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. Assert: value is a Completion Record.
  2. If value is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, value).
  3. Else, set value to ! value.

2 Indexed Collections

2.1 Array Objects

2.1.1 Properties of the Array Constructor

2.1.1.1 Array.fromAsync ( asyncItems [ , mapper [ , thisArg ] ] )

Editor's Note

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

This async method performs the following steps when called:

  1. Let C be the this value.
  2. If mapper is undefined, then
    1. Let mapping be false.
  3. Else,
    1. If IsCallable(mapper) is false, throw a TypeError exception.
    2. Let mapping be true.
  4. Let usingAsyncIterator be ? GetMethod(asyncItems, %Symbol.asyncIterator%).
  5. If usingAsyncIterator is undefined, then
    1. Let usingSyncIterator be ? GetMethod(asyncItems, %Symbol.iterator%).
  6. Let iteratorRecord be undefined.
  7. If usingAsyncIterator is not undefined, then
    1. Set iteratorRecord to ? GetIteratorFromMethod(asyncItems, usingAsyncIterator).
  8. Else if usingSyncIterator is not undefined, then
    1. Set iteratorRecord to CreateAsyncFromSyncIterator(? GetIteratorFromMethod(asyncItems, usingSyncIterator)).
  9. If iteratorRecord is not undefined, then
    1. If IsConstructor(C) is true, then
      1. Let A be ? Construct(C).
    2. Else,
      1. Let A be ! ArrayCreate(0).
    3. Let k be 0.
    4. Repeat,
      1. If k ≥ 253 - 1, then
        1. Let error be ThrowCompletion(a newly created TypeError object).
        2. Return ? AsyncIteratorClose(iteratorRecord, error).
      2. Let Pk be ! ToString(𝔽(k)).
      3. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
      4. Set nextResult to ? Await(nextResult).
      5. If nextResult is not an Object, throw a TypeError exception.
      6. Let done be ? IteratorComplete(nextResult).
      7. If done is true, then
        1. Perform ? Set(A, "length", 𝔽(k), true).
        2. Return A.
      8. Let nextValue be ? IteratorValue(nextResult).
      9. If mapping is true, then
        1. Let mappedValue be Completion(Call(mapper, thisArg, « nextValue, 𝔽(k) »)).
        2. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
        3. Set mappedValue to Completion(Await(mappedValue)).
        4. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
      10. Else,
        1. Let mappedValue be nextValue.
      11. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)).
      12. IfAbruptCloseAsyncIterator(defineStatus, iteratorRecord).
      13. Set k to k + 1.
  10. Else,
    1. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object.
    2. Let arrayLike be ! ToObject(asyncItems).
    3. Let len be ? LengthOfArrayLike(arrayLike).
    4. If IsConstructor(C) is true, then
      1. Let A be ? Construct(C, « 𝔽(len) »).
    5. Else,
      1. Let A be ? ArrayCreate(len).
    6. Let k be 0.
    7. Repeat, while k < len,
      1. Let Pk be ! ToString(𝔽(k)).
      2. Let kValue be ? Get(arrayLike, Pk).
      3. Set kValue to ? Await(kValue).
      4. If mapping is true, then
        1. Let mappedValue be ? Call(mapper, thisArg, « kValue, 𝔽(k) »).
        2. Set mappedValue to ? Await(mappedValue).
      5. Else,
        1. Let mappedValue be kValue.
      6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
      7. Set k to k + 1.
    8. Perform ? Set(A, "length", 𝔽(len), true).
    9. Return A.
Note

This method 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.