Search code examples
javascriptes6-promise

How and when Promise `.then`, `.catch` and `.finally` land in EventLoop micro-tasks queue?


Are .then, .catch and .finally land in JS Event Loop immediately after being registered (when appropriate code is interpreted by JS runtime) or somehow differently?

The less theoretical face of this question is the following :

I have the following code ( Link to JSBin (online JS execution environment) )

l = console.log

const g = (title) => {
    return (a) => {
      l(title + a)
      return a+1;
    }
};

const gA = g("A ")
const gB = g("B ")

const throwError = (title) => {
    return (a) => {
      l(title + a)
      throw new Error("Error from promise " + title + a)
    }
}; 

promise = new Promise((resolve, reject) => {
  resolve(1)
})

l("Started application")

promise
  .then(gA)
  .then(gA)
  .then(throwError("A "))
  .catch(err => {
    l(err.message);
  })


promise
  .then(throwError("B "))
  .then(gB)
  .then(gB)
  .catch(err => {
    l(err.message);
  })

l("Finish main function")

that resolves to the following output in the console

"Started application"
"Finish main function"
"A 1"
"B 1"
"A 2"
"A 3"
"Error from promise A 3"
"Error from promise B 1"

If promise callbacks were to be executed in the order they were registered, I would expect "Error from promise B 1" to be higher in this output. But they appear in the end. Why is this happening?


Solution

  • Do .then, .catch and .finally land in JS Event Loop immediately after being registered or somehow differently?

    Those promise methods themselves never land in the queue. The task queue contains promise reactions, which basically say "run callbacks X/Y on the result of promise Z". (And they're always pairs of then callbacks, as that's what catch and finally use internally).

    These promise reactions are scheduled as soon as the promise is settled, or scheduled immediately during the then call when promise already was settled.

    If promise callbacks were to be executed in the order they were registered

    They are. But this holds only per promise. The only promise in your code that you are attaching multiple callbacks to is promise, and gA does run earlier than throwError("B "). There are no guarantees for callbacks that are attached to different promises, as those promises would settle at different times anyway.