Supongamos que tengo dos funciones asincrónicas, A y B, que son independientes entre sí.

Lo que intento hacer es ejecutar estas funciones secuencialmente varias veces como se muestra a continuación

A -> B -> A -> B -> A -> ... 

B espera hasta que A termine y viceversa.

Lo siguiente es lo que he hecho hasta ahora y sé que no va a funcionar de la manera que quiero.

function A() {
  var promise = new Promise...
  ...
  return promise;
}

function B() {
  var promise = new Promise...
  ...
  return promise;
}

for(var i=0; i<200; i++) {
  var p1 = A();
  p1.then(() => {
   var p2 = B();
   // ----
  }
}

¿Cómo debo cambiar el código?

1
d-_-b 1 nov. 2017 a las 13:38

3 respuestas

La mejor respuesta

Estás yendo por el camino correcto, pero debes seguir encadenando los then s. Por lo general, comienza con una promesa resuelta previamente de Promise.resolve() y luego agrega a la cadena usando then, manteniendo cada nueva promesa:

let p = Promise.resolve();
for (var i=0; i<200; i++) {
  p = p.then(A).then(B);
}
p.then(() => {
  console.log("All done");
});

Ejemplo en vivo (con 20 en lugar de 200):

let counterA = 0;
let counterB = 0;

function A() {
  var promise = new Promise(resolve => {
    setTimeout(() => {
      ++counterA;
      console.log("A done (" + counterA + ")");
      resolve();
    }, 100);
  });
  return promise;
}

function B() {
  var promise = new Promise(resolve => {
    setTimeout(() => {
      ++counterB;
      console.log("B done (" + counterB + ")");
      resolve();
    }, 100);
  });
  return promise;
}

let p = Promise.resolve();
for (var i=0; i<20; i++) {
  p = p.then(A).then(B);
}
p.then(() => {
  console.log("All done");
});
.as-console-wrapper {
  max-height: 100% !important;
}

(En el código real, tendría un .catch también para manejar los rechazos, por supuesto; o estaría devolviendo la última promesa a otro código que los manejaría).

6
T.J. Crowder 1 nov. 2017 a las 10:51

Puede encadenar llamadas con {{X0 }} para asegurarse de que se llamen después de que se hayan realizado las anteriores.

let cA = cB = 0;
function A() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve("A " + ++cA);
            console.log("A done");
        }, 200);
    });
}

function B() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve("B " + ++cB);
            console.log("B done");
        }, 300);
    });
}

function callConsecutive(times) {
    if (times == 0) return Promise.resolve([]);
    times--;
    const a = A(),
          b = a.then(B),
          c = b.then(() => { return callConsecutive(times) });
    return Promise.all([a, b, c]).then(([r1,r2,r3]) => Promise.resolve([r1,r2,...r3]));
}
callConsecutive(5).then(results => { console.log(results); })
1
Ozan 1 nov. 2017 a las 20:28

Puedes hacerlo con una función recursiva

function seqAB(count) {
  if(!count) Promise.resolve();
  var p1 = A();
  p1.then(() => {
    var p2 = B();
    p2.then(() => {
      seqAB(count - 1);
    })
  })
}


seqAB(200);
0
Arun Ghosh 1 nov. 2017 a las 13:09