Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 508
Tim Scott Avatar asked Jan 27 '17 21:01

Tim Scott


People also ask

Does Promise all use multiple threads?

Often Promise. all() is thought of as running in parallel, but this isn't the case. Parallel means that you do many things at the same time on multiple threads. However, Javascript is single threaded with one call stack and one memory heap.

Can Promise be chained?

Example 2: Chaining the Promise with then() Promise resolved You can call multiple functions this way. In the above program, the then() method is used to chain the functions to the promise. The then() method is called when the promise is resolved successfully. You can chain multiple then() methods with the promise.

Is Promise all synchronous or asynchronous?

The fulfillment value is an array of fulfillment values, in the order of the promises passed, regardless of completion order. If the iterable passed is non-empty but contains no pending promises, the returned promise is still asynchronously (instead of synchronously) fulfilled.


2 Answers

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);
    });
});
like image 147
Alexander Staroselsky Avatar answered Oct 06 '22 23:10

Alexander Staroselsky


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.

like image 42
lonesomeday Avatar answered Oct 06 '22 23:10

lonesomeday