Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass results of Promise.join handler in .then() chain

This is similar to, but not quite the same as How do I access previous promise results in a .then() chain?

I have a situation where I am making two async requests in parallel, followed by a third async request which depends on the success of the first two, and finally passing the results of the second async request to the function callback.

As of now I understand how to do this in two ways (.catch statements and function signatures omitted for brevity):

  1. Using scope closure (my current implementation)

    var foo;
    Promise.join(promiseA, promiseB, function(resultsA, resultsB) {
      foo = resultsB;
      return promiseC;
    })
    .then(function() {
      // foo is accessible here
      callback(null, foo);
    });
    
  2. Using Promise.bind, but have to use Promise.map instead of Promise.join

    var targetIndex = 1;
    Promise.resolve(promises)
      .bind({})
      .map(function(response, index) {
        if (index === targetIndex) {
          this.foo = response;
        }
      })
      .then(function() {
        return promiseC;
      })
      .then(function() {
        // this.foo is accessible here
        callback(null, this.foo);
      });
    

As you can tell, option 2 is rather ugly since I have to manually check if the index parameter of the mapper matches the index of the promise result that I care about. Option 1 uses scope closure, which I understand is undesirable in most cases (but seems to be my best option at this point).

What I would really like to do is something like:

Promise.bind({})
  .join(promiseA, promiseB, function(resultsA, resultsB) {
     this.foo = resultsB;
     return promiseC;
  })
  .then(function() {
    // I WISH this.foo WAS ACCESSIBLE HERE!
    callback(null, this.foo);
  });

Is there a way for me to utilize Promise.join instead of Promise.map to avoid using a scope closure in this situation?

like image 706
thedevkit Avatar asked Dec 11 '25 12:12

thedevkit


1 Answers

You have a interesting use case since a Promise needs the result of a promise multiple steps back in the chain. For such a "backward" problem, I would recommend a "backward" solution; adding resultB back into the chain after promiseC:

Promise.join(promiseA, promiseB, function(resultA, resultB) {
  return promiseC.then(function() {
    return resultB;
  });
})
.then(function(resultB) {
  callback(null, resultB);
});

Ideally, promiseC should result in resultB, but that's now always possible.

Edit: Note that I didn't used nested promises on purpose here. The anonymous function is there only to pass values, not execute logic. This approach does the same thing:

...
return promiseC.then(function() {
  callback(null, resultB); // really not what you should be doing
});

but is discouraged because it added a layer of nested logic which ruins the design principle of chaining.

Edit 2: This can be achieved using bound closures like:

Promise.join(promiseA, promiseB).bind({})
.then(function(resultA, resultB) {
  this.resultB = resultB;
  return promiseC;
})
.then(function(resultC) {
  callback(null, this.resultB);
});
like image 169
tcooc Avatar answered Dec 14 '25 02:12

tcooc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!