简体   繁体   中英

In Javascript, why evaluating a `then` method on a “resolved” Promise returns a “pending” Promise?

Following is the native Javascript code:

var first = Promise.resolve(1);
first.then((i)=>console.log(1))

When I inspect first in the console of Chrome, it shows its status is "resolved"

> first
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}

However, when I inspect first.then((i)=>console.log(1)) in the console of Chrome, it shows that its status is "pending"

> first.then((i)=>console.log(1))
1
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

This looks confusing to me because I expected the first.then((i)=>console.log(1)) has the status of resolved as the callback within the then method has already been executed and finished.

Does anyone have ideas about this?

Promise.resolve().then(fn) returns a new promise that is not yet resolved, but will be resolved on the next tick after the current thread of execution unwinds and finishes.

Thus, if you immediately check to see if the returned promise is yet resolved, it will not be. But, if you wait until the next tick, it will then be resolved and the .then() handler function will be fired at that time.

To explain, each chained call to .then() returns a new promise that is chained to the prior one. And, per the Promise A+ specification, all .then() callback handlers are fired asynchronously after the stack has unwound (technically it says something like "when only platform code is on the stack").

So, .then() runs immediately and synchronously. It stores the callback(s) you pass it in the promise object and then those callbacks are actually called asynchronously some time in the future. If the promise is resolved quickly, then the fulfill callback will be called on the next "tick" when the current thread of execution has finished.

This stack unwinding and firing on the next tick is to make it so that .then() handlers are consistently firing asynchronously, not matter how quickly the promise is resolved. This allows the calling code to be written in one consistent manner when the promise is resolved immediately, in 1ms or in 20 minutes. They will all get resolved asynchronously some time in the future and thus the calling code can treat them all the same. The only thing that will be different is how long from now they are resolved or rejected.

For promises that confirm to Promise/A+ spec , for a then call of the form

promise.then(onFulfilled, onRejected)

there is a condition that

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

So, assuming Chrome adheres to this spec for its promises, and only sets the (internal?) Promise status to resolved once the callbacks have been called, calling

Promise.resolve(1).then(onFulfilled, onRejected);

will always show an unresolved promise since the stack has not yet cleared and the callbacks not yet called. However,

var derived = Promise.resolve(1).then(onFulfilled, onRejected);

And then later, in the inspector calling

derived;

will show a resolved promise since the stack has cleared and the callbacks called. The call to

Promise.resolve(1);

is not subject to the constraint on having to wait for the stack to clear, and so returns an immediately resolved promise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM