1

Suppose I have two asynchronous functions, A and B, which are independent to each other.

What I am trying to do is that execute these functions sequentially multiple time as shown below

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

B waits until A finishes and vice versa.

The following is what I have done so far and I know it is not going to work the way I want.

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();
   // ----
  }
}

How should I change the code?

0

3 Answers 3

6

You're headed the right way, but you need to keep chaining the thens. You generally start with a pre-resolved promise from Promise.resolve() then add to the chain using then, keeping each new promise:

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

Live Example (with 20 instead of 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;
}

(In real code, you'd have a .catch as well to handle rejections, of course; or you'd be returning the last promise to other code that would handle them.)

Sign up to request clarification or add additional context in comments.

Comments

1

You can chain calls with chained .then() to make sure they are called after the previous ones are done.

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); })

5 Comments

Don't forget to return your promises, though.
@Bergi, I didn't?
There are four functions in your code that do something asynchronous, but only two of them return a promise. It should be all of them.
@Ozan: callConsecutive doesn't return the last promise it gets, which means calling code can't observe completion and/or handle errors.
OP's question didn't give me the impression that he wanted to access the collective results from outside the A() and B(), just that they wanted to make sure their async functions were called in order, but you are right that it is just better practice in general to have them accessible from the callConsecutive(). So, I edited the callConsecutive to return a promise that accumulates the results.
0

You can do it with a recursive function

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


seqAB(200);

2 Comments

Don't forget to return your promises, though
new Promise(resolve => resolve()); => Promise.resolve();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.