Promises aren't being processed directly, but are based on a queue. If the promise completes, the callback is processed in the next processing cycle.
If we were to replace your code with a more verbose one, we would get:
const a = Promise.resolve('a');
const b = a.then(() => {
console.log('b');
const c = Promise.resolve('c');
return c;
});
const ca = b.then((res) => {
console.log('ca', res)
})
const u = Promise.resolve('u');
const v = u.then(() => {
console.log('v');
});
const w = v.then(() => {
console.log('w');
});
const x = w.then(() => {
console.log('x');
});
const y = x.then(() => {
console.log('y');
});
const z = y.then(() => {
console.log('z');
});
First pass the code is running top to bottom and not a lot is going on. Two promises are being put in the queue as resolved (a
and u
) and nothing is printed. When those are being processed in the next cycle, they queue both b
and v
.
Whenever the next cycle is being processed, b
is first up, logs "b"
and queues the c
. After that, v
is processed, logs "v"
and queues w
.
Now, c
is done, and queues the next ca
(indirection, because of returning a promise in a promise), but doesn't print anything. And so on.
All the way down, it would looks something like this:
// Main tick
// - queue a
// - queue u
// Queue tick
// - resolve a, queues b
// - (log nothing)
// - resolve u, queues v
// - (log nothing)
// Queue tick
// - resolve b, queues c
// - log "b"
// - resolve v, queues w
// - log "v"
// Queue tick
// - resolve c, doesnt log, queues the next (ca)
// - resolve w, queues x
// - log "w"
// Queue tick
// - resolve x, queues y
// - log "x"
// - resolve ca, queues nothing
// - log "ca, c"
// Queue tick
// - resolve y, queues z
// - log "y"
// Queue tick
// - resolve z
// - log "z"
I'm not aware whether this is an actual requirement or not, so the order may change if the implementation (browser) decides to process promises directly. I think its unlikely though, as it doesn't encourage fairness and in case of a promise being chained forever and forever this promise would get all the resources assigned to it.
I think the general recommendation is to not depend on the order of promises being completed. Just think of a.then(b)
as, b
only happens after a
is completed, not earlier, and nothing more.
If you require multiple promises to be dependent on each other, use Promise.all()
or Promise.any()
.