0

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.

9
  • stackoverflow.com/questions/54441138/… is a similar question, but I don't find the answers satisfactory. Commented Sep 12, 2020 at 17:08
  • 1
    Yes, they run in the order they are attached, but that holds only for handles attached to the same promise. Your chained .then() calls return a new promise each time, and they fulfill at different points in time. Commented Sep 12, 2020 at 17:11
  • How is chaining .then() calls directly on a promise different than doing it on separate lines, like I did in the first example? I.e. I don't get why the two examples I posted have different behavior. Commented Sep 12, 2020 at 17:15
  • It's the difference between const prom1 = Promise.resolve(); prom1.then(…); prom1.then(…); and const prom1 = Promise.resolve(); const prom2 = prom1.then(…); prom2.then(…); Notice that prom1 !== prom2 in there. Commented Sep 12, 2020 at 17:20
  • Sorry, I don't get how that example clarifies my question. Here's your example: hastebin.com/eqotilucag.js. This already makes sense to me. Commented Sep 12, 2020 at 17:24

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.