关于 Promise 执行顺序的一个问题?

代码: new Promise(function(resolve){ console.log('promise begin') for( var i=0 ; i<10000 ; i++ ){ i==5000 && console.log('loop...') i==9999 && resolve() } console.log('promise end') }).then(function(){ console.log('callback') }) console.log('other...') 结果: promise begin loop... promise end other... callback 疑问: Promise 里执行的应该都是同步代码? 为什么是先打印 other 后打印 callback…
关注者
52
被浏览
6,151

6 个回答

then(fn)并不立即执行fn,而是把fn放进一个队列(Promise的Job Queue),这个队列的执行优先级低于JS栈,fn被放入队列后,console.log立即执行,进入调用栈,fn必须等待console.log执行完后才能执行。

把代码稍稍改动一下或许可以帮助理解
.then(function(){
    console.log('callback')
}) // 放入队列,等待调用栈空闲

console.log('other...'); // 放入调用栈,立即执行(阻塞队列)

改成

.then(function(){ (1)
    console.log('callback')
}) // 放入队列,等待调用栈空闲

setTimeout(function() { (2)
  console.log('other...');
}, 0); // 放入调用队列,在(1)之后

// 执行到此调用栈空出(没有后续语句)
// 队列中(1)进入调用栈执行
// 然后是(2)
// 这个时候就是先输出callback再输出other。

参考文档:Promise.prototype.then的实现细节
ecma-international.org/
ecma-international.org/
ecma-international.org/

参考书:JavaScript with Promises
ECMA标准里面说明
FulfillPromise ( promise, value )
...
7.Return TriggerPromiseReactions(reactions, value).

TriggerPromiseReactions ( reactions, argument )
...
1.Repeat for each reaction in reactions, in original insertion order
Perform EnqueueJob("PromiseJobs", PromiseReactionJob, «reaction, argument»).
2.Return undefined.
调用过程是FulfillPromise执行后,TriggerPromiseReactions被调用,所有的reactions(promise有结果后应该执行的操作集)都将通过EnqueueJob的方式进入队列。

Jobs and Job queues
Execution of a Job can be initiated only when there is no running execution context and the execution context stack is empty.
在所有的执行栈中的内容处理完成之前Jobs是不会被处理的



额外的补充:
关于最终的输出内容为什么是这样的,下面是一个大致的执行过程。

1.new运算符:使用new运算符创建promise实例p过程中,Promise函数将作为构造函数执行,循环开始,并且最终调用resolve,p的最终结果p._state = fulfilled。

2.then(onFulfilled, onRejected)
then函数中可以看作新建了一个Promise实例p1。then执行过程中发现p._state为fulfilled,将执行resolve(p1),将onFulfilled入队。

3.console.log('other...');
then函数执行完成后执行这条打印函数

4.所有的执行栈内容都已经完成,取出队列任务继续执行

参考内容:
实现Promise - Superlin's Blog
一种Promise实现,比看ECMA的标准要轻松地多,但是觉得实现不是完全标准。。