4

I need to pass a variable through a promise .then chain. I can't find a way to work it out. I'm quite new to this so bear with me!

return foo.bar(baz)
         .then((firstResult) => {
           let message = firstResult;
         })
         .then(() => foo.bar(qux)
           .then((secondResult) => {
             message =+ secondResult;
             console.log(message);
           })
         )

What's the correct way of doing this please?

Matt Sanders
  • 8,023
  • 3
  • 37
  • 49
Nathan Liu
  • 284
  • 5
  • 13
  • 1
    Possible duplicate of [Passing Variables Through a Promise Chain](https://stackoverflow.com/questions/41903625/passing-variables-through-a-promise-chain) – Kiran Joshi Jul 05 '18 at 12:39
  • The 'let' variable has lost its scope in the promise chain. – Sivcan Singh Jul 05 '18 at 12:52
  • Lots of different options illustrated here, depending upon the actual circumstances of your real code: [How to chain and share prior results with promises](https://stackoverflow.com/questions/28714298/how-to-chain-and-share-prior-results-with-promises/28714863#28714863) – jfriend00 Jul 05 '18 at 13:54
  • Do your operations have to go in this specific order? Or could they be run in parallel? – jfriend00 Jul 05 '18 at 13:57
  • @jfriend00 They can run in parallel, as long as the result can be used together. But I'd probably rather do them separately as they are calls into a database that I don't want to bog down. Thanks for your link. – Nathan Liu Jul 05 '18 at 15:00
  • This question is very comprehensively answered [here](https://stackoverflow.com/questions/28250680/how-do-i-access-previous-promise-results-in-a-then-chain). – Roamer-1888 Jul 09 '18 at 08:34

4 Answers4

6

Don't use a promise chain for this.

You are making two, independent calls to foo.bar() and neither of them depend on the results of the other.

Make them independently, and get all their data at the end with Promise.all.

var promises = [
    foo.bar(baz),
    foo.bar(qux)
];
Promise.all(promises).then( results => {
    let message = results[0] + results[1];
    console.log(message);
});
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Thank you, this appears to be the best option. – Nathan Liu Jul 05 '18 at 14:59
  • @NathanLiu - This runs them in parallel which you said you prefer not to in your comment. Jonas' answer runs them sequentially. This probably gets the result a little faster and your database should be able to handle multiple requests just fine. – jfriend00 Jul 05 '18 at 20:22
3

Just make one chain into the callback of the other:

 return foo.bar(baz).then((firstResult) => {
    let message = firstResult; 
    return foo.bar(qux).then((secondResult) => {
       message =+ secondResult;
       console.log(message);
       return message;
    });
});
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

I'll explain why your code didn't work.

The scope of the 'let' variable remains between those brackets that you've put. Thus, in the next .then() that message variable has lost its scope and you couldn't get it to work.

Read the docs here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

To solve your issue you can declare the variable outside the promise chain and write it like so:

let message; // Declare it outside so that the variable is in scope throughout the promise chain

return foo
  .bar(baz)
  .then((firstResult) => {
    message = firstResult; // Set the value here
  })
  .then(() => foo
    .bar(qux)
    .then((secondResult) => {
      message += secondResult;
      console.log(message);
    }));

Refer to the following for a working example: https://jsfiddle.net/sivcan/h3pguw4e/

Sivcan Singh
  • 1,775
  • 11
  • 15
  • Unfortunately this doesn't seem to work. message is null. – Nathan Liu Jul 05 '18 at 14:58
  • @NathanLiu Well, that was because I copied your code and didn't check it further below. My bad. `message = +secondResult` is wrong. It should be `message += secondResult` Here, check it out: https://jsfiddle.net/sivcan/h3pguw4e/ – Sivcan Singh Jul 06 '18 at 07:05
0

You need to call foo.bar(qux) only after foo.bar(baz) has completed.

This is how you call an asynchronous function inside another:

return foo.bar(baz).then((firstResult) => {
    let message = firstResult;
    // do some operation with firstResult
    foo.bar(qux).then((secondResult) => {
      message =+ secondResult;
      console.log(message);
    });
});                       

Better approach: You can create an array of promise then consume it using Promise.all() like this:

var promises = [
    foo.bar(baz),
    foo.bar(qux)
];

Promise.all(promises.map(p => p.catch(error => null))).then( results => {
    let firstResult = results[0]
    let secondResult = results[1];
    console.log("firstResult -->", firstResult);
    console.log("secondResult -->", secondResult );
});                               
BlackBeard
  • 10,246
  • 7
  • 52
  • 62