JS事件循环中两个Promise交叉执行机制及then返回值差异疑问
首先第一个测试场景的理解完全正确:
- 两个Promise同步构造时立刻resolve,各自的第一个
then回调按代码书写顺序依次进入微任务队列,微任务队列遵循先进先出规则执行 - 每个
then回调执行完后,会把当前Promise链的下一个then回调推入微任务队列末尾,所以最终两个Promise的回调交替执行,和你看到的输出一致。
第二个场景核心逻辑
前置知识点
当then回调返回普通值(undefined、字符串、数字等非thenable值)时,当前then返回的Promise会立刻敲定状态,直接把下一个then的回调推入微任务队列。
但如果返回的是已经敲定状态的Promise实例(比如Promise.resolve()),则需要经过两次额外的微任务周转才能把状态传递给外层then返回的Promise,才会触发下一个then回调:
- 第一次:JS引擎生成
PromiseResolveThenableJob微任务,处理返回的Promise和外层Promise的状态绑定 - 第二次:调用返回的Promise的内置
then方法,将外层Promise的resolve函数作为回调传入,这个回调的执行本身又是一个微任务
这两次周转的间隙里,微任务队列中已存在的其他微任务(也就是promiseA的各个then回调)会按顺序先执行,就出现了你看到的间隔现象。
逐阶段执行流程
我们按代码执行顺序逐一对应输出:
- 同步代码执行阶段
- 构造promiseA,立刻resolve,第一个
then回调(输出promiseA - 1)进入微任务队列 - 构造promiseB,resolve参数为
Promise.resolve(),需要先处理这个传入Promise的状态传递,因此promiseB的第一个then回调暂不入队,先插入一个状态传递微任务
- 构造promiseA,立刻resolve,第一个
- 微任务执行阶段
- 执行promiseA第一个回调,输出
promiseA - 1,将promiseA-2回调推入队列 - 执行promiseA-2回调,输出
promiseA - 2,将promiseA-3回调推入队列 - 执行promiseA-3回调,输出
promiseA - 3,将promiseA-4回调推入队列;此时promiseB的初始状态传递完成,promiseB第一个回调入队 - 执行promiseB第一个回调,输出
Promise.resolve() - 1;返回的Promise.resolve()需要两次状态传递微任务,暂不推入下一个then回调 - 执行promiseA-4回调,输出
promiseA - 4,将promiseA-5回调推入队列 - 执行promiseA-5回调,输出
promiseA - 5,将promiseA-6回调推入队列 - 执行promiseA-6回调,输出
promiseA - 6,将promiseA-7回调推入队列;此时promiseB第一个回调返回的Promise状态传递完成,promiseB第二个回调入队 - 执行promiseB第二个回调,输出
Promise.resolve() - 2;内部Promise.resolve().then(() => console.log('then'))的回调入队,同时返回的Promise需要两次状态传递微任务,暂不推入下一个then回调 - 执行promiseA-7回调,输出
promiseA - 7,将promiseA-8回调推入队列 - 执行Promise内部的then回调,输出
then - 执行promiseA-8回调,输出
promiseA - 8,将promiseA-9回调推入队列 - 执行promiseA-9回调,输出
promiseA - 9;此时promiseB第二个回调返回的Promise状态传递完成,promiseB第三个回调入队 - 执行promiseB第三个回调,输出
Promise.resolve() - 3
- 执行promiseA第一个回调,输出
你观察到的“3轮事件循环”不是固定规则,只是刚好两次状态传递的微任务间隙里,promiseA的两个回调被执行,加上状态传递完成后promiseB回调执行前的那个promiseA回调,刚好凑够3个promiseA的输出间隔。
内容的提问来源于stack exchange,提问作者smellycat
相关产品推荐
相关产品推荐

