Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

121
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda