Skip to content

Async Iterator Helpers on Async Generators #1366

Open
@nikolaybotev

Description

@nikolaybotev

Hi @zloirock,

I have been thinking hard about what the best way is to make Async Iterator Helpers (through your polyfills) as widely available in an as easy manner as possible.

Just for context, as you describe in the README, the problem is that unlike iterator helpers, for async iterator helpers it is not possible to retrieve a reference to the (currently hidden) async iterator prototype object (without using modern syntax, which core-js is constrained from using). So the following does not work out of the box:

require("core-js/proposals/async-iterator-helpers");

async function* gen() {
  yield* [1, 2, 3, 4, 5];
}

gen()
  .drop(1)
  .take(3)
  .filter(n => n != 3)
  .map(n => n * 10)
  .forEach(n => console.log(n));

On modern runtimes with async generator syntax, this can be fixed by leveraging the configurator, with the following snippet at the top of the script:

{
  const asyncGeneratorInstancePrototype = Object.getPrototypeOf(async function*(){}());
  const AsyncGeneratorPrototype = Object.getPrototypeOf(asyncGeneratorInstancePrototype);
  const AsyncIteratorPrototype = Object.getPrototypeOf(AsyncGeneratorPrototype);
  require("core-js/configurator")({ AsyncIteratorPrototype });
}

On older runtimes, when transpiling using babel's standard preset-env, the above does not work, because the transpiler does not install the full standard prototype chain on async generator objects. Luckily, this can be worked around fairly simply, like so:

{
  const asyncGeneratorInstancePrototype = Object.getPrototypeOf(async function*(){}());
  const AsyncGeneratorPrototype = Object.getPrototypeOf(asyncGeneratorInstancePrototype);
  let AsyncIteratorPrototype;
  if (AsyncGeneratorPrototype === Object.prototype) {
    // Fix-up for babel's transform-async-generator-functions
    AsyncIteratorPrototype = {};
    Object.setPrototypeOf(asyncFunctionPrototype, AsyncIteratorPrototype);
  } else {
    AsyncIteratorPrototype = Object.getPrototypeOf(AsyncGeneratorPrototype);
  }
  require("core-js/configurator")({ AsyncIteratorPrototype });
}

Also, it should not be too difficult to fix the transpiler to provide the proper prototype chain, especially since this has already been done for regular generators in the regenerator library, whose approach can be adopted for async generators. Then the above setup code makes async iterator helpers readily available on async generators in all environments. It is also future-proof, in that when async iterator helpers become implemented by runtimes, the native AsyncIterator constructor will be used.

My question then is this: do you think it is reasonable to add a babel plugin (say proposal-async-iterator-helpers, which installs the above snippet in code during transpilation, and runs before the async generator function transformer)? Or do you think there is a better approach?

Thanks for the attention.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions