简体   繁体   中英

Concurrent chained javascript promises

I have javascript promises A and C where B is a function that returns a promise. This is how I'd like them to flow:

A--->B--->
C-------->
          D------>

B utilizes output from A, and D utilizes output from B and C

My current code looks roughly as so:

var runPromises = [];
runPromises.push(A.then(B));
runPromises.push(C);

Promise.all(runPromises).then(values => console.log(values));

What I'm seeing happen is A and C execute but B does not until after A and C are logged out. What is the proper pattern here for execution? Do A and B need to be put in an encompassing promise?

To add on to my original question to explain Jaromanda's correct answer: My B function was defined roughly as so:

var B = function(inputA){
    return new Promise(function(resolve, reject){
        http.get(site, function(done){
            inputA['site'] = done;
        }
    resolve(inputA);

This was resolving inputA before the http.get could return and enrich inputA.

if A, B and C are promises, then A.then(B) will return A as the result. The argument to .then must be FUNCTION, not a promise

What you want to do is something like

Promise.all([A.then(result=>B), C]).then(values => console.log(values));

If B is a FUNCTION (as per the comment below) rather than a PROMISE (as per the question), it's a simple change:

Promise.all([A.then(result=>B()), C]).then(values => console.log(values));
//---------------------------^^

or more simply

Promise.all([A.then(B), C]).then(values => console.log(values));

which is basically what you had in the question - so I'm now confused as to what the problem is? Is it the values shown in the console.log?

 var delay = (timeout, value) => new Promise(resolve => { setTimeout(() => {resolve(value); console.log('done', value);}, timeout); console.log('begin', value) }); var A = delay(3000, 'valueOfA'); // A is a Promise var C = delay(2000, 'valueOfC'); // C is a Promise var B = valA => { console.log('B called with', valA); return delay(1000, valA + ':valueOfB'); // include valA to show that the resolved value of B depends on the resolved value of A } // B is a function that returns a Promise and uses the resolved value of A as input Promise.all([A.then(B),C]).then(values => console.log(values)); 

To chain promises, you can use .then() , but the parameter needs to be a function that returns the next Promise. The correct code would be:

var runPromises = [];
runPromises.push(A.then(() => B));
runPromises.push(C);

Promise.all(runPromises).then(values => console.log(values));

As mentioned by the other answers, if we assume "B" is a function that sets up a promise, and not a promise itself, you are correct that "B" should execute without relying on "C". You can prove this out with a small test:

let start = Date.now();
function debug(p) {
  p.then((r) => {
    let secs = ((Date.now() - start) / 1000).toFixed(2)
    console.log(secs + "s: " + r);
  });
}

let a = new Promise((r) => {
  setTimeout(r, 0, "a done");
});
debug(a);

let b = a.then((res) => {
  return new Promise((r) => {
    setTimeout(r, 0, res + ":b done");
  });
});
debug(b);

let c = new Promise((r) => {
  setTimeout(r, 1000, "c done");
});
debug(c);

Promise.all([b, c]).then((res) => {
  console.log("result: " + JSON.stringify(res));
});

Results in:

0.00s: a done
0.01s: a done:b done
1.00s: c done
result: ["a done:b done","c done"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM