Promise.resolve(1)
.then(x => console.log(1))
.catch(x => console.log(2))
.then(x => console.log(3))
Promise.reject(2)
.then(x => console.log(4))
.catch(x => console.log(6))
.then(x => console.log(7))
result is "1 6 3 7", but if i add another then() before catch with console.log(6) result will be 1 3 6 7, i dont't understand why
Promise.resolve(1)
.then(x => console.log(1))
.catch(x => console.log(2))
.then(x => console.log(3))
Promise.reject(2)
.then(x => console.log(4))
.then(x => console.log(5))
.catch(x => console.log(6))
.then(x => console.log(7))
result is 1 3 6 7
i'm trying to understand how it works
Promise listeners are run by a Promise task runner job put in the Promise Job Queue when a promise becomes fulfilled or rejected. HTML 5 uses the microtask queue for the Promise Job Queue, and the queue operates as a FIFO (first in first out).
Promise Jobs are run consecutively, after other JavaScript has returned to the event loop, until the Promise Job queue is empty.
The purpose of a promise job is to pass the value or rejection reason of the promise that created the job onto the next promise in a chain of promises.
If the promise spawning the job is fulfilled, the next promise will be fulfilled with the same value, and if rejected, rejected with the same reason. If a promise listener returns a promise, the next promise is resolved with the promise returned.
Passing on promise state and value to next promises is performed using internally stored¹ values of their resolve
and reject
functions.
It's important to note that catch
clauses are shorthand² for a two argument call to then
. Whether a clause in the source code says then
or catch
, promise jobs are still created to resolve, fulfill or reject the promise object that the clause returned.
Putting all this together should allow predicting the sequence of promise listener executions in cases when multiple promise chains are being processed at the same time.
The first example inter-meshes promise jobs in the following sequence:
The second example also inter-meshes program jobs but with a different alignment:
Moral of the story? Don't depend on the execution order of multiple jobs in the promise queue, by breaking promise chains into smaller chains if you need partial completion results.
¹ About resolve
and reject
functions for chained promises.
resolve
and reject
functions for promises returned by calling their then
, catch
and finally
methods.² About then
calls with one argument
then(listenerFunction)
is equivalent to then(listenerFunction, null)
. Applied to a rejected promise, null
as the rejection handler causes the next promise in a chain to be rejected with the same reason.catch(listenerFunction)
is equivalent to then(null, listenerFunction)
. Applied to a fulfilled promise, null
as the fulfillment handler causes the next promise in a chain to be fulfilled with the same value.Promise chain clauses that don't apply to the settled state of a previous promise in a chain are not skipped - they actively pass on the state and value of the previous promise to the next promise within a promise job entered into the microtask queue for that purpose.