Why Promise.resolve().then() is delayed?

2019-01-28 00:45发布

问题:

I don't understand why resoved Promise delay .then() argument call?

example:

var myPromise = Promise.resolve();
console.log(myPromise);
myPromise.then(()=>console.log('a'));
console.log('b');

console return:

> Promise { <state>: "fulfilled", <value>: undefined }
> "b"
> "a"

If myPromise is fulfilled, why .then() don't call imediatly resolve function?

回答1:

Because, by specification, promises call their resolve handler AFTER the current thread of execution unwinds and finishes back to "platform code". That guarantees that they are always called asynchronously.

So, thus you see the console.log('b') first as that thread of execution finishes and then the resolve handler is called where you see the console.log('a').

From the Promises/A+ specification:

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

And, here's note [3.1]:

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.

This is done to provide consistent execution order so no matter when the promise is resolved (synchronously or asynchronously), the then() handlers are always called in the same timing relative to other code. Since many promises are resolved asynchronously, the only way to make a given promise consistent no matter how it is resolved is to make them always call their .then() handlers asynchronously.



回答2:

jfriend00's answer is correct. Allow me to elaborate on why. Let's say I got myPromise from somewhere. I don't know it's just a Promise.resolve, it might resolve asynchronously, and it might not.

myPromise.then(function(){
     console.log("a");
});
console.log("b");

If the asynchronousity guarantee didn't exist - that would sometimes log a b and sometimes b a. This is a race condition, and is a terrible thing to have. Promises are not susceptible to this problem by design - and execution order is always guaranteed in new promises implementations and native promises in particular.

The actual implementation of running new jobs is via Job Queues. then enqueues a job to the job queue in the handler, and job queues are run after code is ready - this is specified here.