2

When I execute the following code, the block of code A gets executed before the block of code B.

return new Promise((resolve, reject) => {
  try {
    resolve()
  } finally {
    // block of code A
  }
}).then(() => {
  // block of code B
})

But I don't understand why A is executed first.

The resolution (or rejection) of a promise triggers the then corresponding to it, so I would expect block of code B to be run before block of code A.

From the doc:

When either of these options (resolve/reject) happens, the associated handlers queued up by a promise's then method are called.

I also read this:

the executor is called before the Promise constructor even returns the created object

the executor = the function passed as param to the Promise object.

The latter quote makes me think that the try catch can be finished before the resolution or rejection handlers are triggered (before the executor function is returned from the Promise). It would explain that the finally is triggered before the Promise's then.

HOWEVER, I tried making a call to an external API with fetch and awaiting for the response before continuing, hoping that the Promise function would widely have the time to return the executor function before the try catch is finished:

return new Promise(async (resolve, reject) => {
  try {
    await fetch('https://swapi.co/api/people/1/')
    resolve()
  } finally {
    // block of code A
  }
}).then(() => {
  // block of code B
})

And it turned out that A was still executed before B. I expected the resolution handler to be triggered before A is executed, since resolve is called before A is executed. But I am wrong, and I don't understand why.

May someone explain me please?

papillon
  • 1,807
  • 2
  • 19
  • 39
  • try by putting the promise inside the try blocking – brk Nov 26 '18 at 13:53
  • have you tried `.then().then()`? – Ali Sajid Nov 26 '18 at 13:57
  • 2
    you are confusing `try/catch/finally` with `Promise.protoype.finally`. Also wrapping `fetch()` in new Promise is an anti-pattern – charlietfl Nov 26 '18 at 14:03
  • @charlietfl could you explain how wrapping fetch() in new Promise is an anti-pattern please? – papillon Nov 26 '18 at 15:09
  • Basically because `fetch()` returns a promise itself https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it – charlietfl Nov 26 '18 at 15:10
  • thank's for the link. I had a harsh time understand half of it, but I feel like I start to understand. If I need to do several fetches and some response data's formatting in my try block, is it antipattern? I don't see any other way to do it. – papillon Nov 26 '18 at 16:55
  • 1
    [Never pass an `async function` as the executor to `new Promise`](https://stackoverflow.com/q/43036229/1048572)! – Bergi Jan 14 '21 at 17:09

2 Answers2

2

The promise constructor is always executed synchronously. This means any code inside it will execute right away.

A then block queues a function to execute after the promise is resolved. The function you passed to then runs after all synchronous code.

console.log(1);
Promise.resolve().then(() => console.log(3));
console.log(2); // logs 1, 2, 3

The spec calls this EnqueueJob. Note that you should avoid explicit construction when creating promise returning function. An async function already returns a promise automatically.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • If a `then` block queues a function to execute after the promise is resolved, and if the promise is resolved synchronously, the code inside the `then` should be executed immediatly after the promise is resolved (synchronously)? If so, how comes your third line is executed before the function inside the `then`? – papillon Nov 26 '18 at 15:59
  • Moreover when I put a `await fetch('...')` in the finally, it seems like it is considered as asynchronous while it is not when written in the try block... I don't understand this. – papillon Nov 26 '18 at 17:06
  • "the code inside the then should be executed immediatly after the promise is resolved (synchronously)" - no, it is always deferred. This is a feature to prevent race conditions and different order of execution in case the promise settles synchronously. – Benjamin Gruenbaum Nov 30 '18 at 13:27
0

The finally{} block is part of the try catch block. So, if you have more than one set of try catch block, then each set can have their own finally block, which will get executed when either the try block is finished or the corresponding catch block is finished.

Sonal Borkar
  • 531
  • 1
  • 6
  • 12