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.