Reputation: 859
I run the code sample bellow on my machine (with Node 5.8.0 installed) and get next result (see after the code sample).
Code sample:
'use strict'
var p1 = Promise.resolve();
var p2 = Promise.resolve();
var p12 = Promise.all([p1, p2]);
var cb = function() {
console.log(p12);
}
setTimeout(cb, 0);
console.log(p1);
console.log(p2);
console.log(p12);
Result:
Promise { undefined }
Promise { undefined }
Promise { <pending>
}
Promise { [ undefined, undefined ] }
Why is it so that p12 not resolved immediately after p1 and p2 (giving p1 and p1 resolved at the start of the program), and why is 'timeouted' p12 got resolved? Is there some amount of time needed for Promise.all(array) gets resolved?
Upvotes: 3
Views: 147
Reputation: 707318
Per the promise specification, a promise fulfill or reject handler is always called asynchronously AFTER the event loop has finished its current cycle. Thus, p12
is not resolved immediately even though the arguments to it are all resolved promises. So, it won't get resolved until shortly after this event loop finishes. This explains why your first statement:
console.log(p12);
shows that the promise is still "pending". It's current .then()
handlers (if any) have not yet been called. However, once the current thread of code finishes executing and control returns back to the next event in the event queue, the promise will then be resolved and thus your setTimeout()
sees it as resolved by then.
This is done for caller consistency reasons so that .then()
handlers are called consistently in an asynchronous manner no matter whether the promise was already resolved or is not yet resolved. This allows the calling code to always code consistently without worrying about whether the promise might already be resolved. In all cases .then()
handlers are called after the current stack unwinds and finishes.
From the Promises/A+ specification:
onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
So, the upshot of all this is that promises ALWAYS resolve asynchronously after the current thread of execution has finished. Though the internal details may be a bit more complicated than this (perhaps involving micro-tasks), you can logically think of a promise getting resolved by posting a message to the event queue that it is now awaiting being resolved/rejected. And, whenever the event queue finishes what is currently running and gets a turn to run the promises .then()
handlers, only then will they execute.
Upvotes: 4