Stage 2 Draft / October 24, 2022

Iterator Helpers

Contributing to this Proposal

This proposal is developed on GitHub with the help of the ECMAScript community. There are a number of ways to contribute to the development of this specification:

1 Well-Known Intrinsic Objects

Table 1: Well-Known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%AsyncIterator% AsyncIterator The AsyncIterator constructor (3.1.3.1)
%AsyncIteratorPrototype% AsyncIterator.prototype An object that all standard built-in async iterator objects indirectly inherit from

The initial value of the "prototype" data property of %AsyncIterator%; i.e., %AsyncIterator.prototype%

%Iterator% Iterator The Iterator constructor (3.1.2.1)
%IteratorPrototype% Iterator.prototype An object that all standard built-in iterator objects indirectly inherit from

The initial value of the "prototype" data property of %Iterator%; i.e., %Iterator.prototype%

2 Abstract Operations

2.1 Operations on Iterator Objects

2.1.1 GetIteratorDirect ( obj )

The abstract operation GetIteratorDirect takes argument obj (an ECMAScript language value) and returns either a normal completion containing an Iterator Record or a throw completion. It performs the following steps when called:

  1. If obj is not an Object, throw a TypeError exception.
  2. Let nextMethod be ? Get(obj, "next").
  3. If IsCallable(nextMethod) is false, throw a TypeError exception.
  4. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
  5. Return iteratorRecord.

2.1.2 GetIteratorFlattenable ( obj, hint )

The abstract operation GetIteratorFlattenable takes arguments obj (an ECMAScript language value) and hint (sync or async) and returns either a normal completion containing an Iterator Record or a throw completion. It performs the following steps when called:

  1. If obj is not an Object, throw a TypeError exception.
  2. Let alreadyAsync be false.
  3. Let method be undefined.
  4. If hint is async, then
    1. Set method to ? Get(obj, @@asyncIterator).
    2. Set alreadyAsync to true.
  5. If IsCallable(method) is false, then
    1. Set method to ? Get(obj, @@iterator).
    2. Set alreadyAsync to false.
  6. If IsCallable(method) is false, then
    1. Let iterator be obj.
    2. Set alreadyAsync to true.
  7. Else,
    1. Let iterator be ? Call(method, obj).
  8. Let nextMethod be ? GetV(iterator, "next").
  9. If IsCallable(nextMethod) is false, throw a TypeError exception.
  10. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
  11. If hint is async and alreadyAsync is false, then
    1. Return CreateAsyncFromSyncIterator(iteratorRecord).
  12. Return iteratorRecord.

3 Control Abstraction Objects

3.1 Iteration

3.1.1 Iterator Abstract Operations

3.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. If value is an abrupt completion, then
    1. Perform ? AsyncIteratorClose(iteratorRecord, value).
    2. Return value.
  2. Else if value is a Completion Record, set value to value.[[Value]].

3.1.1.2 AwaitNonPrimitive ( value )

The abstract operation AwaitNonPrimitive takes argument value (an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. If value is an Object, return ? Await(value).
  2. Else, return value.

3.1.2 Iterator Objects

3.1.2.1 The Iterator Constructor

The Iterator constructor:

  • is %Iterator%.
  • is the initial value of the Iterator property of the global object.
  • is designed to be subclassable. It may be used as the value of an extends clause of a class definition.

3.1.2.1.1 Iterator ( )

When the Iterator function is called, the following steps are taken:

  1. If NewTarget is undefined or the active function object, throw a TypeError exception.
  2. Return ? OrdinaryCreateFromConstructor(NewTarget, "%Iterator.prototype%").

3.1.2.2 Properties of the Iterator Constructor

3.1.2.2.1 Iterator.prototype

The initial value of Iterator.prototype is %Iterator.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

3.1.2.2.2 Iterator.from ( O )

  1. Let iteratorRecord be ? GetIteratorFlattenable(O, sync).
  2. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
  3. If hasInstance is true, then
    1. Return iteratorRecord.[[Iterator]].
  4. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
  5. Set wrapper.[[Iterated]] to iteratorRecord.
  6. Return wrapper.

3.1.2.2.2.1 The %WrapForValidIteratorPrototype% Object

The %WrapForValidIteratorPrototype% object:

3.1.2.2.2.1.1 %WrapForValidIteratorPrototype%.next ( )

  1. Let O be this value.
  2. Perform ? RequireInternalSlot(O, [[Iterated]]).
  3. Let iteratorRecord be O.[[Iterated]].
  4. Return ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).

3.1.2.2.2.1.2 %WrapForValidIteratorPrototype%.return ( )

  1. Let O be this value.
  2. Perform ? RequireInternalSlot(O, [[Iterated]]).
  3. Let iterator be O.[[Iterated]].[[Iterator]].
  4. Assert: iterator is an Object.
  5. Let returnMethod be ? GetMethod(iterator, "return").
  6. If returnMethod is undefined, then
    1. Return CreateIterResultObject(undefined, true).
  7. Return ? Call(returnMethod, iterator).

3.1.3 AsyncIterator Objects

3.1.3.1 The AsyncIterator Constructor

The AsyncIterator constructor:

  • is %AsyncIterator%.
  • is the initial value of the AsyncIterator property of the global object.
  • is designed to be subclassable. It may be used as the value of an extends clause of a class definition.

3.1.3.1.1 AsyncIterator ( )

When the AsyncIterator function is called, the following steps are taken:

  1. If NewTarget is undefined or the active function object, throw a TypeError exception.
  2. Return ? OrdinaryCreateFromConstructor(NewTarget, "%AsyncIterator.prototype%").

3.1.3.2 Properties of the AsyncIterator Constructor

3.1.3.2.1 AsyncIterator.prototype

The initial value of AsyncIterator.prototype is %AsyncIterator.prototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

3.1.3.2.2 AsyncIterator.from ( O )

  1. Let iteratorRecord be ? GetIteratorFlattenable(O, async).
  2. Let hasInstance be ? OrdinaryHasInstance(%AsyncIterator%, iteratorRecord.[[Iterator]]).
  3. If hasInstance is true, then
    1. Return iteratorRecord.[[Iterator]].
  4. Let wrapper be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »).
  5. Set wrapper.[[AsyncIterated]] to iteratorRecord.
  6. Return wrapper.

3.1.3.2.2.1 The %WrapForValidAsyncIteratorPrototype% Object

The %WrapForValidAsyncIteratorPrototype% object:

3.1.3.2.2.1.1 %WrapForValidAsyncIteratorPrototype%.next ( )

  1. Let O be this value.
  2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  3. Let check be Completion(RequireInternalSlot(O, [[AsyncIterated]])).
  4. IfAbruptRejectPromise(check, promiseCapability).
  5. Let result be Completion(IteratorNext(O.[[AsyncIterated]])).
  6. IfAbruptRejectPromise(result, promiseCapability).
  7. Return ? PromiseResolve(%Promise%, result).

3.1.3.2.2.1.2 %WrapForValidAsyncIteratorPrototype%.return ( )

  1. Let O be this value.
  2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  3. Let check be Completion(RequireInternalSlot(O, [[AsyncIterated]])).
  4. IfAbruptRejectPromise(check, promiseCapability).
  5. Let iterator be O.[[AsyncIterated]].[[Iterator]].
  6. Assert: iterator is an Object.
  7. Let returnMethod be Completion(GetMethod(iterator, "return")).
  8. IfAbruptRejectPromise(returnMethod, promiseCapability).
  9. If returnMethod is undefined, then
    1. Return ! PromiseResolve(%Promise%, CreateIterResultObject(undefined, true)).
  10. Let result be Completion(Call(returnMethod, iterator)).
  11. IfAbruptRejectPromise(result, promiseCapability).
  12. Return ? PromiseResolve(%Promise%, result).

3.1.4 Iterator Helper Objects

An Iterator Helper object is an ordinary object that represents a lazy transformation of some specific source iterator object. There is not a named constructor for Iterator Helper objects. Instead, Iterator Helper objects are created by calling certain methods of Iterator instance objects.

3.1.4.1 The %IteratorHelperPrototype% Object

The %IteratorHelperPrototype% object:

3.1.4.1.1 %IteratorHelperPrototype%.next ( )

  1. Return ? GeneratorResume(this value, undefined, "Iterator Helper").

3.1.4.1.2 %IteratorHelperPrototype%.return ( )

  1. Let C be Completion { [[Type]]: return, [[Value]]: undefined, [[Target]]: empty }.
  2. Return ? GeneratorResumeAbrupt(this value, C, "Iterator Helper").

3.1.4.1.3 %IteratorHelperPrototype% [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Iterator Helper".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

3.1.5 Async Iterator Helper Objects

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.

3.1.5.1 The %AsyncIteratorHelperPrototype% Object

The %AsyncIteratorHelperPrototype% object:

3.1.5.1.1 %AsyncIteratorHelperPrototype%.next ( )

  1. Return AsyncGeneratorNext(this value, "Async Iterator Helper", undefined).

3.1.5.1.2 %AsyncIteratorHelperPrototype%.return ( )

  1. Return AsyncGeneratorReturn(this value, "Async Iterator Helper", undefined).

3.1.5.1.3 %AsyncIteratorHelperPrototype% [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Async Iterator Helper".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

3.1.6 Iterator.prototype

The Iterator prototype object:

3.1.6.1 Iterator.prototype.constructor

The initial value of %Iterator.prototype%.constructor is %Iterator%.

3.1.6.2 Iterator.prototype.map ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(mapped, iterated).
      6. Let completion be Completion(Yield(mapped)).
      7. IfAbruptCloseIterator(completion, iterated).
      8. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.6.3 Iterator.prototype.filter ( filterer )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(filterer) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and filterer and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let selected be Completion(Call(filterer, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(selected, iterated).
      6. If ToBoolean(selected) is true, then
        1. Let completion be Completion(Yield(value)).
        2. IfAbruptCloseIterator(completion, iterated).
      7. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.6.4 Iterator.prototype.take ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat,
      1. If remaining is 0, then
        1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
      2. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      3. Let next be ? IteratorStep(iterated).
      4. If next is false, return undefined.
      5. Let completion be Completion(Yield(? IteratorValue(next))).
      6. IfAbruptCloseIterator(completion, iterated).
  7. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.6.5 Iterator.prototype.drop ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat, while remaining > 0,
      1. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      2. Let next be ? IteratorStep(iterated).
      3. If next is false, return undefined.
    3. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let completion be Completion(Yield(? IteratorValue(next))).
      4. IfAbruptCloseIterator(completion, iterated).
  7. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.6.6 Iterator.prototype.flatMap ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? IteratorStep(iterated).
      2. If next is false, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseIterator(mapped, iterated).
      6. Let innerIterator be Completion(GetIteratorFlattenable(mapped, sync)).
      7. IfAbruptCloseIterator(innerIterator, iterated).
      8. Let innerAlive be true.
      9. Repeat, while innerAlive is true,
        1. Let innerNext be Completion(IteratorStep(innerIterator)).
        2. IfAbruptCloseIterator(innerNext, iterated).
        3. If innerNext is false, then
          1. Set innerAlive to false.
        4. Else,
          1. Let innerValue be Completion(IteratorValue(innerNext)).
          2. IfAbruptCloseIterator(innerValue, iterated).
          3. Let completion be Completion(Yield(innerValue)).
          4. If completion is an abrupt completion, then
            1. Let backupCompletion be Completion(IteratorClose(innerIterator, completion)).
            2. IfAbruptCloseIterator(backupCompletion, iterated).
            3. Return ? IteratorClose(completion, iterated).
      10. Set counter to counter + 1.
  4. Return CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%).

3.1.6.7 Iterator.prototype.reduce ( reducer [ , initialValue ] )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(reducer) is false, throw a TypeError exception.
  3. If initialValue is not present, then
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, throw a TypeError exception.
    3. Let accumulator be ? IteratorValue(next).
    4. Let counter be 1.
  4. Else,
    1. Let accumulator be initialValue.
    2. Let counter be 0.
  5. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return accumulator.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(reducer, undefined, « accumulator, value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. Set accumulator to result.[[Value]].
    7. Set counter to counter + 1.

3.1.6.8 Iterator.prototype.toArray ( )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let items be a new empty List.
  3. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return CreateArrayFromList(items).
    3. Let value be ? IteratorValue(next).
    4. Append value to items.

3.1.6.9 Iterator.prototype.toAsync ( )

This method performs the following steps when called:

  1. Let syncIteratorRecord be ? GetIteratorDirect(this value).
  2. Let asyncIteratorRecord be CreateAsyncFromSyncIterator(syncIteratorRecord).
  3. Let wrapper be OrdinaryObjectCreate(%WrapForValidAsyncIteratorPrototype%, « [[AsyncIterated]] »).
  4. Set wrapper.[[AsyncIterated]] to asyncIteratorRecord.
  5. Return wrapper.

3.1.6.10 Iterator.prototype.forEach ( fn )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. Set counter to counter + 1.

3.1.6.11 Iterator.prototype.some ( fn )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return false.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(true)).
    7. Set counter to counter + 1.

3.1.6.12 Iterator.prototype.every ( fn )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return true.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
    7. Set counter to counter + 1.

3.1.6.13 Iterator.prototype.find ( fn )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? IteratorStep(iterated).
    2. If next is false, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseIterator(result, iterated).
    6. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
    7. Set counter to counter + 1.

3.1.6.14 Iterator.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Iterator".

Note

Unlike the @@toStringTag on most built-in classes, for web-compatibility reasons this property must be writable.

3.1.7 AsyncIterator.prototype

The AsyncIterator prototype object:

3.1.7.1 AsyncIterator.prototype.constructor

The initial value of AsyncIterator.prototype.constructor is %AsyncIterator%.

3.1.7.2 AsyncIterator.prototype.map ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? Await(? IteratorNext(iterated)).
      2. If ? IteratorComplete(next) is true, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseAsyncIterator(mapped, iterated).
      6. Set mapped to Completion(AwaitNonPrimitive(mapped)).
      7. IfAbruptCloseAsyncIterator(mapped, iterated).
      8. Let completion be Completion(Yield(mapped)).
      9. IfAbruptCloseAsyncIterator(completion, iterated).
      10. Set counter to counter + 1.
  4. Return CreateAsyncIteratorFromClosure(closure, "Async Iterator Helper", %AsyncIteratorHelperPrototype%).

3.1.7.3 AsyncIterator.prototype.filter ( filterer )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(filterer) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and filterer and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? Await(? IteratorNext(iterated)).
      2. If ? IteratorComplete(next) is true, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let selected be Completion(Call(filterer, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseAsyncIterator(selected, iterated).
      6. Set selected to Completion(AwaitNonPrimitive(selected)).
      7. IfAbruptCloseAsyncIterator(selected, iterated).
      8. If ToBoolean(selected) is true, then
        1. Let completion be Completion(Yield(value)).
        2. IfAbruptCloseAsyncIterator(completion, iterated).
      9. Set counter to counter + 1.
  4. Return CreateAsyncIteratorFromClosure(closure, "Async Iterator Helper", %AsyncIteratorHelperPrototype%).

3.1.7.4 AsyncIterator.prototype.take ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat,
      1. If remaining is 0, then
        1. Return ? AsyncIteratorClose(iterated, NormalCompletion(undefined)).
      2. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      3. Let next be ? Await(? IteratorNext(iterated)).
      4. If ? IteratorComplete(next) is true, return undefined.
      5. Let completion be Completion(Yield(? IteratorValue(next))).
      6. IfAbruptCloseAsyncIterator(completion, iterated).
  7. Return CreateAsyncIteratorFromClosure(closure, "Async Iterator Helper", %AsyncIteratorHelperPrototype%).

3.1.7.5 AsyncIterator.prototype.drop ( limit )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let numLimit be ? ToNumber(limit).
  3. If numLimit is NaN, throw a RangeError exception.
  4. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
  5. If integerLimit < 0, throw a RangeError exception.
  6. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
    1. Let remaining be integerLimit.
    2. Repeat, while remaining > 0,
      1. If remaining is not +∞, then
        1. Set remaining to remaining - 1.
      2. Let next be ? Await(? IteratorNext(iterated)).
      3. If ? IteratorComplete(next) is true, return undefined.
    3. Repeat,
      1. Let next be ? Await(? IteratorNext(iterated)).
      2. If ? IteratorComplete(next) is true, return undefined.
      3. Let completion be Completion(Yield(? IteratorValue(next))).
      4. IfAbruptCloseAsyncIterator(completion, iterated).
  7. Return CreateAsyncIteratorFromClosure(closure, "Async Iterator Helper", %AsyncIteratorHelperPrototype%).

3.1.7.6 AsyncIterator.prototype.flatMap ( mapper )

This method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(mapper) is false, throw a TypeError exception.
  3. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
    1. Let counter be 0.
    2. Repeat,
      1. Let next be ? Await(? IteratorNext(iterated)).
      2. If ? IteratorComplete(next) is true, return undefined.
      3. Let value be ? IteratorValue(next).
      4. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
      5. IfAbruptCloseAsyncIterator(mapped, iterated).
      6. Set mapped to Completion(AwaitNonPrimitive(mapped)).
      7. IfAbruptCloseAsyncIterator(mapped, iterated).
      8. Let innerIterator be Completion(GetIteratorFlattenable(mapped, async)).
      9. IfAbruptCloseAsyncIterator(innerIterator, iterated).
      10. Let innerAlive be true.
      11. Repeat, while innerAlive is true,
        1. Let innerNextPromise be Completion(IteratorNext(innerIterator)).
        2. IfAbruptCloseAsyncIterator(innerNextPromise, iterated).
        3. Let innerNext be Completion(Await(innerNextPromise)).
        4. IfAbruptCloseAsyncIterator(innerNext, iterated).
        5. Let innerComplete be Completion(IteratorComplete(innerNext)).
        6. IfAbruptCloseAsyncIterator(innerComplete, iterated).
        7. If innerComplete is true, then
          1. Set innerAlive to false.
        8. Else,
          1. Let innerValue be Completion(IteratorValue(innerNext)).
          2. IfAbruptCloseAsyncIterator(innerValue, iterated).
          3. Let completion be Completion(Yield(innerValue)).
          4. If completion is a return completion, then
            1. Let backupCompletion be Completion(IteratorClose(innerIterator, completion)).
            2. IfAbruptCloseIterator(backupCompletion, iterated).
            3. Return ? IteratorClose(completion, iterated).
          5. Else if completion is a throw completion, then
            1. Assert: Awaiting innerValue during the Yield on step 3.b.xi.8.c threw.
            2. Return ? IteratorClose(completion, iterated).
      12. Set counter to counter + 1.
  4. Return CreateAsyncIteratorFromClosure(closure, "Async Iterator Helper", %AsyncIteratorHelperPrototype%).

3.1.7.7 AsyncIterator.prototype.reduce ( reducer [ , initialValue ] )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(reducer) is false, throw a TypeError exception.
  3. If initialValue is not present, then
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, throw a TypeError exception.
    3. Let accumulator be ? IteratorValue(next).
    4. Let counter be 1.
  4. Else,
    1. Let accumulator be initialValue.
    2. Let counter be 0.
  5. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return accumulator.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(reducer, undefined, « accumulator, value, 𝔽(counter) »)).
    5. IfAbruptCloseAsyncIterator(result, iterated).
    6. Set result to Completion(AwaitNonPrimitive(result)).
    7. IfAbruptCloseAsyncIterator(result, iterated).
    8. Set accumulator to result.
    9. Set counter to counter + 1.

3.1.7.8 AsyncIterator.prototype.toArray ( )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. Let items be a new empty List.
  3. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return CreateArrayFromList(items).
    3. Let value be ? IteratorValue(next).
    4. Append value to items.

3.1.7.9 AsyncIterator.prototype.forEach ( fn )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let r be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseAsyncIterator(r, iterated).
    6. Set r to Completion(AwaitNonPrimitive(r)).
    7. IfAbruptCloseAsyncIterator(r, iterated).
    8. Set counter to counter + 1.

3.1.7.10 AsyncIterator.prototype.some ( fn )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return false.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseAsyncIterator(result, iterated).
    6. Set result to Completion(AwaitNonPrimitive(result)).
    7. IfAbruptCloseAsyncIterator(result, iterated).
    8. If ToBoolean(result) is true, return ? AsyncIteratorClose(iterated, NormalCompletion(true)).
    9. Set counter to counter + 1.

3.1.7.11 AsyncIterator.prototype.every ( fn )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return true.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseAsyncIterator(result, iterated).
    6. Set result to Completion(AwaitNonPrimitive(result)).
    7. IfAbruptCloseAsyncIterator(result, iterated).
    8. If ToBoolean(result) is false, return ? AsyncIteratorClose(iterated, NormalCompletion(false)).
    9. Set counter to counter + 1.

3.1.7.12 AsyncIterator.prototype.find ( fn )

This async method performs the following steps when called:

  1. Let iterated be ? GetIteratorDirect(this value).
  2. If IsCallable(fn) is false, throw a TypeError exception.
  3. Let counter be 0.
  4. Repeat,
    1. Let next be ? Await(? IteratorNext(iterated)).
    2. If ? IteratorComplete(next) is true, return undefined.
    3. Let value be ? IteratorValue(next).
    4. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
    5. IfAbruptCloseAsyncIterator(result, iterated).
    6. Set result to Completion(AwaitNonPrimitive(result)).
    7. IfAbruptCloseAsyncIterator(result, iterated).
    8. If ToBoolean(result) is true, return ? AsyncIteratorClose(iterated, NormalCompletion(value)).
    9. Set counter to counter + 1.

3.1.7.13 AsyncIterator.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Async Iterator".

Note

Unlike the @@toStringTag on most built-in classes, for web-compatibility reasons this property must be writable.

4 New AsyncGenerator AOs

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.

4.1 AsyncGeneratorNext ( generator, brand, value )

The abstract operation AsyncGeneratorNext takes arguments generator, brand, and value (an ECMAScript language value) and returns an ECMAScript language value. It performs the following steps when called:

  1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  2. Let result be Completion(AsyncGeneratorValidate(generator, brand)).
  3. IfAbruptRejectPromise(result, promiseCapability).
  4. Let state be generator.[[AsyncGeneratorState]].
  5. If state is completed, then
    1. Let iteratorResult be CreateIterResultObject(undefined, true).
    2. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iteratorResult »).
    3. Return promiseCapability.[[Promise]].
  6. Let completion be NormalCompletion(value).
  7. Perform AsyncGeneratorEnqueue(generator, completion, promiseCapability).
  8. If state is either suspendedStart or suspendedYield, then
    1. Perform AsyncGeneratorResume(generator, completion).
  9. Else,
    1. Assert: state is either executing or awaiting-return.
  10. Return promiseCapability.[[Promise]].

4.2 AsyncGeneratorReturn ( generator, brand, value )

The abstract operation AsyncGeneratorReturn takes arguments generator, brand, and value (an ECMAScript language value) and returns an ECMAScript language value. It performs the following steps when called:

  1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  2. Let result be Completion(AsyncGeneratorValidate(generator, brand)).
  3. IfAbruptRejectPromise(result, promiseCapability).
  4. Let completion be Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
  5. Perform AsyncGeneratorEnqueue(generator, completion, promiseCapability).
  6. Let state be generator.[[AsyncGeneratorState]].
  7. If state is either suspendedStart or completed, then
    1. Set generator.[[AsyncGeneratorState]] to awaiting-return.
    2. Perform ! AsyncGeneratorAwaitReturn(generator).
  8. Else if state is suspendedYield, then
    1. Perform AsyncGeneratorResume(generator, completion).
  9. Else,
    1. Assert: state is either executing or awaiting-return.
  10. Return promiseCapability.[[Promise]].