Skip to content

Async iterator from iterator of promises via racing #21

@bakkot

Description

@bakkot

This proposal will include Iterator.prototype.toAsync, which takes a potentially-infinite iterator of values. Calling .next() on the result will call .next() on the underlying thing, await the result and yield it - basically lifting { done: boolean, value: Promise<T> } to Promise<{ done: boolean, value: T }>.

Another way to do it is to take a finite iterator of values, await all of them simultaneously, and yield the results in the order in which they settle. Basically:

async function* raced(promises) {
  while (promises.length > 0) {
    let [p, i] = await Promise.race(promises.map((p, i) => p.then(v => [v, i])));
    promises.splice(i, 1);
    yield p;
  }
}

let sleep = ms => new Promise(res => setTimeout(res, ms));
let promises = [sleep(200).then(x => 2), sleep(100).then(x => 1), sleep(300).then(x => 3)];
for await (let item of raced(promises)) {
  console.log(item);
}
// prints 1, 2, 3

I'm sure this has been proposed before, but I can't find it.

It probably doesn't make sense to put it in this version of the proposal, but since it is similar in signature to toAsync I wanted to mention it anyway.

This is basically sync.toAsync().bufferUnordered(N) with an N set to the length of sync, so it may not make sense to include if we end up adding bufferUnordered. Eh, actually, you don't necessarily know the length of an arbitrary iterator, so I think this is still warranted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions