Passing Variables Through a Promise Chain [duplicate]

Is there a better way to do this?

let foo;
return functionA().then(result => {
  foo = result;
  return functionB();
}).then(bar => {
  return functionC(foo, bar);
});

Notice that the result of functionA is required input to functionC. Using a variable outside the promise scope works fine, but it feels kinda icky. Is there a clean idiomatic way to do this?

Please note that I do not have the opportunity to change the API of any of the functions I am calling.

Answers:

Answer

You could try using Promise.all() which you can pass an array of promises and it provides an array of responses within the then() callback when all promises passed in have resolved. You can access those array values to pass into functionC:

Promise.all([functionA, functionB]).then(values => functionC(values[0], values[1]));

Might be a little cleaner (without nesting) as it doesn't look like the response from functionA needs to be passed into functionB.

Otherwise, nesting would look like:

return functionA().then(foo => {
    return functionB().then(bar => {
        return functionC(foo, bar);
    });
});

Hopefully that helps.

Answer

One option is, as Alexander Staroselsky writes, to use Promise.all(functionA(), functionB()). This runs the two functions simultaneously. If that's what you want to happen, you can use that answer. If, however, you want them to happen one after the other and then also be able to pass the result onto another handler, you can do this:

function functionA() {
  return new Promise(resolve => resolve(1));
}

function functionB() {
  return new Promise(resolve => resolve(2));
}

function functionC(first, second) {
  return first + second;
}

functionA()
  .then(result => Promise.all([result, functionB()]))
  .then(function([first, second]) {
    return functionC(first, second);
  })
  .then(result => {
    console.log(result);
  });

The functions are obviously simplified -- but the lovely thing about Promises is that that doesn't matter: we don't care how complex they are or how long they take. Yay Promises!

The clever thing is that Promise.all doesn't mind if the values you pass are not Promises. If they are any other value, they are treated as a Promise that is resolved immediately. (In the same way that you can do Promise.resolve(42).then(...).) So we can do Promise.all([result, functionB()]). This says "give me a Promise that is resolved when you have a final value for both result and functionB() and pass both values on". That is immediately in the case of result and at some unspecified time in the case of functionB.

The returned values are then passed as an array to the next then function.

.then(function([first, second]) {
  return functionC(first, second);
})

This then receives the values as an array (see the use of destructuring in the parameter list) and sends those values on to functionC. We then do one last then function to show the result.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.