Async iterator helpers

Specification
Proposal repo

Modules

esnext.async-iterator.constructor, esnext.async-iterator.drop, esnext.async-iterator.every, esnext.async-iterator.filter, esnext.async-iterator.find, esnext.async-iterator.flat-map, esnext.async-iterator.for-each, esnext.async-iterator.from, esnext.async-iterator.map, esnext.async-iterator.reduce, esnext.async-iterator.some, esnext.async-iterator.take, esnext.async-iterator.to-array, esnext.iterator.to-async

Built-ins signatures

class Iterator {
  toAsync(): AsyncIterator<any>;
}

class AsyncIterator {
  static from(iterable: AsyncIterable<any> | Iterable<any> | AsyncIterator<any>): AsyncIterator<any>;
  drop(limit: uint): AsyncIterator<any>;
  every(async callbackfn: (value: any, counter: uint) => boolean): Promise<boolean>;
  filter(async callbackfn: (value: any, counter: uint) => boolean): AsyncIterator<any>;
  find(async callbackfn: (value: any, counter: uint) => boolean): Promise<any>;
  flatMap(async callbackfn: (value: any, counter: uint) => AsyncIterable<any> | Iterable<any> | AsyncIterator<any>): AsyncIterator<any>;
  forEach(async callbackfn: (value: any, counter: uint) => void): Promise<void>;
  map(async callbackfn: (value: any, counter: uint) => any): AsyncIterator<any>;
  reduce(async callbackfn: (memo: any, value: any, counter: uint) => any, initialValue: any): Promise<any>;
  some(async callbackfn: (value: any, counter: uint) => boolean): Promise<boolean>;
  take(limit: uint): AsyncIterator<any>;
  toArray(): Promise<Array>;
  @@toStringTag: 'AsyncIterator';
}

Entry points

core-js/proposals/async-iterator-helpers
{ core-js, @core-js/pure }/full/async-iterator
{ core-js, @core-js/pure }/full/async-iterator/drop
{ core-js, @core-js/pure }/full/async-iterator/every
{ core-js, @core-js/pure }/full/async-iterator/filter
{ core-js, @core-js/pure }/full/async-iterator/find
{ core-js, @core-js/pure }/full/async-iterator/flat-map
{ core-js, @core-js/pure }/full/async-iterator/for-each
{ core-js, @core-js/pure }/full/async-iterator/from
{ core-js, @core-js/pure }/full/async-iterator/map
{ core-js, @core-js/pure }/full/async-iterator/reduce
{ core-js, @core-js/pure }/full/async-iterator/some
{ core-js, @core-js/pure }/full/async-iterator/take
{ core-js, @core-js/pure }/full/async-iterator/to-array
{ core-js, @core-js/pure }/full/iterator/to-async

TypeScript type definitions

@core-js/types/proposals/async-iterator-helpers

Examples

await AsyncIterator.from([1, 2, 3, 4, 5, 6, 7])
  .drop(1)
  .take(5)
  .filter(it => it % 2)
  .map(it => it ** 2)
  .toArray();  // => [9, 25]

await [1, 2, 3].values().toAsync().map(async it => it ** 2).toArray(); // => [1, 4, 9]

Caveats

  • To prevent prototype pollution, in the pure version, new %AsyncIteratorPrototype% methods are not added to the real %AsyncIteratorPrototype%, they are available only on wrappers - instead of [].values().toAsync().map(fn) use AsyncIterator.from([]).map(fn).
  • Now, we have access to the real %AsyncIteratorPrototype% only by using the async generators syntax. So, for compatibility of the library with old browsers, we should use the Function constructor. However, that breaks compatibility with CSP. So, if you want to use the real %AsyncIteratorPrototype%, you should set USE_FUNCTION_CONSTRUCTOR option in the core-js/configurator to true:
const configurator = require('core-js/configurator');

configurator({ USE_FUNCTION_CONSTRUCTOR: true });

require('core-js/full/async-iterator');

(async function * () { /* empty */ })() instanceof AsyncIterator; // => true
  • As an alternative, you could pass to the core-js/configurator an object that will be considered as %AsyncIteratorPrototype%:
const configurator = require('core-js/configurator');

const { getPrototypeOf } = Object;

configurator({ AsyncIteratorPrototype: getPrototypeOf(getPrototypeOf(getPrototypeOf(async function * () { /* empty */ }()))) });

require('core-js/full/async-iterator');

(async function * () { /* empty */ })() instanceof AsyncIterator; // => true