关于 Promise 异步的执行顺序的问题

setTimeout(() => {
  console.log(0)
})

new Promise(resolve => {
  resolve(1)
  Promise.resolve().then(t => {
    console.log(2)
  })
  console.log(3)
})
.then(t => {
  console.log(t)
})

console.log(4)

为什么是先输出 2 再输出 1?而不是先1再2?求大佬解答,感激不尽!

阅读 2.3k
2 个回答

一旦一个pormise有了结果,或者早已有了结果,他就会为它的回调产生一个微任务。如果在微任务执行期间微任务队列加入了新的微任务,会将新的微任务加入队列尾部,之后也会被执行。

当执行resolve(1)的时候,代码还没运行到then(t => {console.log(t)}),这时候是没有回调的,所以这时候还是没有添加任何微任务的。

接下来执行Promise.resolve().then(t => {console.log(2)}),为已有结果的内层Promise添加一个微任务,然后外层Promise执行.then(t => {console.log(t)}),这时候外层Promise是属于早已有了结果,所以为这个回调添加一个微任务。

输出2的微任务在输出1的微任务前面,所以是先输出 2 再输出 1

在resolve同步调用的情况下,这里的执行顺序和then()的顺序有关,和resolve()的顺序无关。

https://mp.weixin.qq.com/s/VIoUDWq9212WsXweyfH5ZA
这篇文章最后面的例子比你这个还复杂,解释也挺详细,可以看看。

这里涉及到JavaScript执行栈和消息队列的概念(自己先了解一下哈)。

另外还要了解Promise的实现原理。(你可以试着自己实现一个Promise,也有相关文章。但是模拟的时候也是用setTimeout模拟,毕竟无法真正操作到js底层的执行栈和队列,细节效果可能有出入,但有助于理解原理)

下面是解释:
当promise.then(handle)执行后,这个promise进入等待状态,等有了结果,它会在js的消息队列中push一个任务(即这个handle)。等js的其他同步代码执行完了(即执行栈空闲了),再从队列中读取第一个任务handle,依次执行。

而如果promise.then(handle)执行后,这个promise是立刻(同步)返回结果的(同步返回结果或已有结果),它会立刻往队列中push(handle),等待执行,push的顺序影响执行顺序。

你题目中的两个.then(),都是同步返回结果的,所以then()的顺序就影响了push()的顺序,进而影响了执行顺序。与resolve()的顺序无关。

Promise.resolve().then(t => {console.log(2)})
相当于:
Promise.resolve(undefined).then(handle)。
已有了结果“undefined”,.then()的时候就立刻把handle给push到队列了。

xxx.then(t => { console.log(t) })
因为你直接resolve(1),相当于同步返回了结果1,此时也会立刻把handle给push到队列。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题