Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

114
Views
How to read from multiple Async JavaScript generators at the same time

I have a code like this:

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function* foo() {
    yield 1;
    await delay(100);
    yield 2;
    await delay(100);
    yield 3;
    await delay(100);
    yield 4;
    await delay(100);
    yield 5;
    await delay(100);
    yield 6;
    await delay(100);
    yield 7;
    await delay(100);
    yield 8;
    await delay(100);
    yield 9;
    await delay(100);
    yield 10;
}

async function* bar() {
    yield 'a';
    await delay(200);
    yield 'b';
    await delay(200);
    yield 'c';
    await delay(200);
    yield 'd';
    await delay(200);
    yield 'e';
}

(async function () {
    for await (const num of foo()) {
        console.log(num);
    }
    for await (const str of bar()) {
        console.log(str);
    }

    await delay(2000);
})();

which produce:

1
2
3
4
5
6
7
8
9
10
a
b
c
d
e

What addjustments I should make, to read from 2 generators at the same time, and get:

1
2
a
3
4
b
5
6
c
7
8
d
9
10
e
about 4 years ago · Santiago Trujillo
3 answers
Answer question

0

In a comment you said:

I get 2 generators as output from libary which run a binary. One generator is with output (lines of texts, each line yielded at a time), and another generator contains information about progress (numbers from 0 to 100). Of course I want to be able to display progress simultaneously while displaying output.

In that case, loop through the async generators in parallel:¹

async function show(g) {
    for await (const value of g) {
        console.log(value);
    }
}
(async function () {
    // Start processing the first one
    const pFoo = show(foo());
    // Start processing the second one
    const pBar = show(bar());
    // Wait until both are done
    await Promise.all([pFoo, pBar]);
})();

But, note that if you do that with the specific two synthetic generators in your question, the output won't be exactly what you've said you wanted, because foo writes 1 synchronously before waiting 100ms, and similarly bar writes a synchronously before waiting 200ms, so the results start with 1 a 2 b and then continue with 3 4 c 5 6 d 7 8 e and so on. They are interleaved as you've said you wanted, just those synthetic ones don't quite have the timing you were expecting when writing the question.

Live Example:

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function* foo() {
    yield 1;
    await delay(100);
    yield 2;
    await delay(100);
    yield 3;
    await delay(100);
    yield 4;
    await delay(100);
    yield 5;
    await delay(100);
    yield 6;
    await delay(100);
    yield 7;
    await delay(100);
    yield 8;
    await delay(100);
    yield 9;
    await delay(100);
    yield 10;
}

async function* bar() {
    yield "a";
    await delay(200);
    yield "b";
    await delay(200);
    yield "c";
    await delay(200);
    yield "d";
    await delay(200);
    yield "e";
}

async function show(g) {
    for await (const value of g) {
        console.log(value);
    }
}
(async function () {
    const pFoo = show(foo());
    const pBar = show(bar());
    await Promise.all([pFoo, pBar]);
})();
.as-console-wrapper {
    max-height: 100% !important;
}


¹ "Parallel" in async terms. They don't literally run in parallel threads, they interleave (sort of like "cooperative multitasking"). JavaScript restricts its execution semantics to only a single active thread within a given realm ("realm" loosely means global environment and the code in it).

about 4 years ago · Santiago Trujillo Report

0

Similar to TJ's functional approach, you can wrap each loop in an IIFE:

edit note: Originally this answer included promises, hence TJ's comments.

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function* foo() {
    yield 1;
    await delay(100);
    yield 2;
    await delay(100);
    yield 3;
    await delay(100);
    yield 4;
    await delay(100);
    yield 5;
    await delay(100);
    yield 6;
    await delay(100);
    yield 7;
    await delay(100);
    yield 8;
    await delay(100);
    yield 9;
    await delay(100);
    yield 10;
}

async function* bar() {
    yield 'a';
    await delay(200);
    yield 'b';
    await delay(200);
    yield 'c';
    await delay(200);
    yield 'd';
    await delay(200);
    yield 'e';
}

(async function () {
    
    const numPromise = (async () => {
      for await (const num of foo()) {
            console.log(num);
      }
    })();
    
    const strPromise = (async () => {
      for await (const str of bar()){
        console.log(str);
      }
    })();
    
    await Promise.all([numPromise,strPromise])
    console.log('Done!')

      
    await delay(2000);
})();

about 4 years ago · Santiago Trujillo Report

0

Here's a way you can consume them as a single async generator, by using Promise.race on each iteration:

async function* race(iterable) {
  const generators = [...iterable];
  const next = gen => {
    const promise = gen.next().then(
      ({ done, value }) => ({ done, value, gen, promise }),
    );
    return promise;
  };
  const promises = generators.reduce(
    (set, gen) => set.add(next(gen)), new Set(),
  );

  while (promises.size > 0) {
    const { done, value, gen, promise } = await Promise.race(promises);
    promises.delete(promise);

    if (!done) {
      promises.add(next(gen));
      yield value;
    }
  }
}

(async () => {
  for await (const value of race([foo(), bar()])) {
    console.log(value);
  }
})();

function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function* foo() {
  yield 1;
  await delay(100);
  yield 2;
  await delay(100);
  yield 3;
  await delay(100);
  yield 4;
  await delay(100);
  yield 5;
  await delay(100);
  yield 6;
  await delay(100);
  yield 7;
  await delay(100);
  yield 8;
  await delay(100);
  yield 9;
  await delay(100);
  yield 10;
}

async function* bar() {
  yield 'a';
  await delay(200);
  yield 'b';
  await delay(200);
  yield 'c';
  await delay(200);
  yield 'd';
  await delay(200);
  yield 'e';
}

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!