when does Promise.resolve() trigger then() method?

Viewed 627

I'm learning the Promise in js and i have some question about it, here's the code:

Promise.resolve().then(() => {
  console.log(0);
  return Promise.resolve(4);
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() => {
  console.log(6);
})

the output is far from what I expected, i thought it would be 0 1 4 2 3 5 6, because i saw this on MDN

the Promise.resolve() method returns a Promise object that is resolved with a given value

so doesn't the log() method should be triggered right behind number 1?

What am I doing wrong?

1 Answers

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().

Related