I was under the impression that then
handler functions are processed in the order they are added.
For example, if you run this code:
function getResolvedPromise(result) {
return new Promise((resolve, reject) => {
console.log(`Promise executor, result will be ${result}`);
resolve(result);
});
}
function logThen(label, result) {
console.log(`[${label}] Promise then, result = ${result}`);
return result;
}
// Shows that then handlers get run in the order they are added.
const prom1 = getResolvedPromise("prom1");
const prom2 = getResolvedPromise("prom2");
prom2.then(logThen.bind(null, "1"));
prom2.then(logThen.bind(null, "2"));
prom2.then(logThen.bind(null, "3"));
prom1.then(logThen.bind(null, "4"));
prom1.then(logThen.bind(null, "5"));
prom1.then(logThen.bind(null, "6"));
Then this is what gets logged. This makes sense to me.
Promise executor, result will be prom1
Promise executor, result will be prom2
[1] Promise then, result = prom2
[2] Promise then, result = prom2
[3] Promise then, result = prom2
[4] Promise then, result = prom1
[5] Promise then, result = prom1
[6] Promise then, result = prom1
However, if you run this:
// Order of execution is interleaved when then handlers are directly attached?
const prom1 = getResolvedPromise("prom1")
.then(logThen.bind(null, "1"))
.then(logThen.bind(null, "2"))
.then(logThen.bind(null, "3"));
const prom2 = getResolvedPromise("prom2")
.then(logThen.bind(null, "4"))
.then(logThen.bind(null, "5"))
.then(logThen.bind(null, "6"));
Then this is what gets logged.
Promise executor, result will be prom1
Promise executor, result will be prom2
[1] Promise then, result = prom1
[4] Promise then, result = prom2
[2] Promise then, result = prom1
[5] Promise then, result = prom2
[3] Promise then, result = prom1
[6] Promise then, result = prom2
What explains this interleaving behavior?
Note that the specification contains some relevant information here. Specifically, it says this about HostEnqueuePromiseJob:
Jobs must run in the same order as the HostEnqueuePromiseJob invocations that scheduled them.
And if we look at the specification for Promise.prototype.then
, we see that it calls HostEnqueuePromiseJob. So the only way this makes sense to me is that the then
calls are being called in an interleaved order. But... I don't really get how this happens, since the two code samples I posted seem equivalent to me.