Promise的then方法返回Promise对象时的执行顺序问题
问题解答
核心结论
console.log(4)输出在3之后,本质是**then回调返回Promise实例时,会触发额外的微任务调度流程,导致后续链式then的执行延后了2个微任务周期**。
测试代码
Promise.resolve().then(() => { console.log(0); return Promise.resolve(4); }).then((res) => { console.log(res) }) Promise.resolve().then(() => { console.log(1); }).then(() => { console.log(2); }).then(() => { console.log(3); }).then(() => { console.log(5); }).then(() =>{ console.log(6); })
执行流程拆解
JS中微任务队列遵循先进先出规则执行,按阶段拆解执行过程:
- 初始阶段:两个
Promise.resolve()均为已决议状态,它们的第一个then回调依次入队,微任务队列:[打印0的回调, 打印1的回调] - 执行第一个微任务:打印
0,返回已决议的Promise.resolve(4)(记为p4)。此时触发规范定义的PromiseResolveThenableJob微任务入队,作用是绑定p4的决议结果到外层Promise。当前微任务队列:[打印1的回调, PromiseResolveThenableJob] - 执行下一个微任务:打印
1,回调无特殊返回值,下一个打印2的then回调直接入队。微任务队列:[PromiseResolveThenableJob, 打印2的回调] - 执行
PromiseResolveThenableJob:读取到p4的决议值为4,此时还需要再生成一个微任务,才能把4传递给外层Promise的下一个then回调,这个微任务入队。微任务队列:[打印2的回调, 触发打印4的微任务] - 执行打印
2的回调,无特殊返回值,打印3的回调入队。微任务队列:[触发打印4的微任务, 打印3的回调] - 执行打印
3的回调,无特殊返回值,打印5的回调入队。微任务队列:[触发打印4的微任务, 打印5的回调] - 执行触发打印4的微任务:打印
4。微任务队列:[打印5的回调] - 依次执行后续微任务,打印
5、6,最终输出顺序为0 1 2 3 4 5 6
then返回Promise的特殊处理逻辑
根据ECMAScript规范,then回调返回值会触发[[Resolve]]抽象操作,当返回值是Promise这类thenable对象时,会有特殊处理:
- 不会直接用这个Promise的结果决议当前
then返回的外层Promise - 会新增一个
PromiseResolveThenableJob微任务入队,专门处理这个返回的Promise的决议逻辑 - 等这个返回的Promise决议完成后,还需要再新增一个微任务,才能把决议结果传递给外层Promise的后续
then回调 - 整个流程比普通返回非thenable值的情况多了2次微任务调度,所以后续
then的执行会延后2个微任务周期
内容的提问来源于stack exchange,提问作者T.T
相关产品推荐
相关产品推荐

