-1

If I'm chaining Promises and I return a Promise from the resolve handler, how does that Promise become the return value of the call to then? What is going on behind the scenes?

In the following example, in firstMethodHandler, the call to secondMethodreceives a new Promise which it then returns, but that promise is then returned from the then method in which it is passed to its promise. How does this happen?

function firstMethod(value) {
  console.log('1st method:', value)
  return new Promise((resolve, reject) => {
    resolve(++value);
  });
}

function secondMethod(value) {
  return new Promise((resolve, reject) => {
    console.log('2nd method:', value)
    resolve(++value);
  });
}

function firstMethodHandler(value) {
  console.log("1st method handler:",value);
  return secondMethod(value);
}

function secondMethodHandler(value) {
  console.log("2nd method handler:", value);
}


firstMethod(1)
  .then(firstMethodHandler)
  .then(secondMethodHandler)
Undistraction
  • 42,754
  • 56
  • 195
  • 331
  • 3
    I'm not sure what you are looking for beyond "that's what the Promise specification says should happen" or "its an implementation detail of the Promise library". – Quentin Jan 22 '17 at 20:35
  • … or "the same way as any other return value is passed as an argument to another function call" – Quentin Jan 22 '17 at 20:40
  • Not certain what specific Question is? See also [Are there differences between .then(functionReference) and .then(function(value){return functionReference(value)})?](http://stackoverflow.com/questions/41191131/are-there-differences-between-thenfunctionreference-and-thenfunctionvalue) – guest271314 Jan 22 '17 at 20:48
  • I think the question is about how promise chaining works and how `.then()` handlers fit into the promise chain. – jfriend00 Jan 22 '17 at 20:53
  • @jfriend00 From perspective here, OP appears to be querying how the `Promise` value is passed to function within `.then()` when only a reference to the function is present? Curious if you have reviewed this Question [Understanding the execution order of subsequent then() handlers of an resolved promise](http://stackoverflow.com/questions/41788626/understanding-the-execution-order-of-subsequent-then-handlers-of-an-resolved-p) ? – guest271314 Jan 22 '17 at 20:56
  • @guest271314 - I have not reviewed that (I was sleeping when it was posted). I think some of that question is answered by my answer here. – jfriend00 Jan 22 '17 at 20:58

1 Answers1

1

The key here is that p1.then() returns a new promise we will call p2. When p1 is resolved, it calls the .then() handler attached to it. When you return another promise from that .then() (which we will call p3), then p3 is chained to p2 and thus p2 will not be resolved until p3 resolves. So, the caller of the original p1.then() will get back a promise p2 that won't be resolved until both p1 and p3 are resolved. That's how things are chained together.

Usually, the key piece of information here is that p1.then() returns a new promise and it is that promise that is affected by what happens inside the previous .then() handler.

You can see a similar explanation here:

Difference between resolve and return in promise JS


In your specific example:

firstMethod(1)
  .then(firstMethodHandler)
  .then(secondMethodHandler)

firstMethod() returns a promise I will call p1. Then, calling .then(firstMethodHandler) on that promise returns a new promise p2 and then calling .then(secondMethodHandler) on that creates a new promise p3.

At some point in the future, firstMethod() resolves the promise it returned. So, now p1 is resolved. That calls the .then() handler attached to it and thus calls firstMethodHandler(). That returns a new promise p4. That chains p4 to the p2 promise so p2 will not resolve until p4 does. At some point in the future, p4 resolves which allows p2 to resolve. That calls the .then() handler attached to p2 which thus calls secondMethodHandler() and you see the final console.log().

As you can see from the explanation, the key here is the new promises p2 and p3 that are created when .then() is first executed. That's what the chained .then() handlers are actually linked to and those promises are what are influenced by what is returned from the attached .then() handlers.

To see what the chaining is doing, we can remove the actual chaining and show you the actual intermediate variables that are automatically created and used:

var p1 = firstMethod(1);
var p2 = p1.then(firstMethodHandler);
var p3 = p2.then(secondMethodHandler);

p1 is resolved internal to firstMethod() p2 is the return value of p1.then(...) p3 is the return value of p2.then(...)

When firstMethodHandler is called (after p1 resolves), then it returns p4 which is chained to p2 so that p2 does not resolved until p4 resolves. When p4 finally resolves, it allows p2 to resolve which then calls secondMethodHandler. When that .then() handler returns a normal value, then p3 is resolved and the whole chain is done.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • You say 'When you return another promise from that .then()' but this is exactly my question. I don't return a promise from then(). I return it from the function/handler that I passed in to then(). How does this promise end up being returned from then()? I interested in that mechanism. – Undistraction Jan 22 '17 at 21:40
  • 1
    @Pedr - Every call to `.then()` returns a new promise. The return value of `.then()` is a new promise. That's not something you do. That's how `.then()` works. Remember all the calls to `.then()` on the chain are executed immediately and their promises are created immediately. The callbacks passed to `.then()` are registered as event handlers internally so they can be called later. Please read the last four paragraphs of my answer. That shows you all the intermediate promises that are created automatically for you. – jfriend00 Jan 22 '17 at 21:42
  • Thankyou. I think the penny just dropped. I understood that the promise I was returning from the callback was the same promise returned from the call to `then()`, but of course that isn't possible as the `then()` has already returned. I'll pick through your answer and hopefully put my head to bed. – Undistraction Jan 22 '17 at 21:49
  • @Pedr - Yeah, the promises are linked so that resolving one down the chain causes the original one returned far up the chain to eventually get resolved which is what the caller actually sees. It is a bit confusing. Eventually, you just get how the chaining concept works and can just use it without having to make your brain hurt trying to figure out how the chaining is actually implemented. – jfriend00 Jan 22 '17 at 21:54