JavaScript Promise执行顺序疑问:为何4先于2输出?
为什么Promise的then回调输出4早于2?
问题代码
let x = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 0); }) x.then((res) => new Promise(function(resolve, reject){ resolve(res*2); })) .then((res) => console.log(res)) x.then((res) => res*4) .then((res) => console.log(res)) console.log("Out")
问题描述
为何代码输出顺序是 Out → 4 → 2,而非预期的 Out → 2 → 4?明明先调用了第一个then链,为什么第二个链的输出更早?
原因解析
核心在于Promise的then回调返回值类型不同,会导致后续回调进入微任务队列的时机不一样,结合JavaScript事件循环机制拆解如下:
同步代码优先执行
首先执行最外层的console.log("Out"),所以第一个输出是Out。同时创建Promise实例x,并把setTimeout的回调(触发resolve(1))加入宏任务队列。宏任务触发Promise状态变更
同步代码执行完后,事件循环取出宏任务队列里的setTimeout回调执行,把x的状态改为resolved,此时两个绑定在x上的then回调都会被加入当前微任务队列。微任务队列的分批次处理
事件循环开始处理当前微任务队列:- 先执行第一个
x.then的回调:这个回调返回了一个新的Promise实例。虽然这个新Promise的executor函数是同步执行的(立刻调用resolve(res*2)把状态设为resolved),但它的后续then回调(打印2的那个)不会加入当前微任务队列,而是要等当前微任务队列清空后,进入下一轮微任务队列。 - 接着执行第二个
x.then的回调:这个回调返回的是普通数值4,Promise会自动把这个值包装成状态为resolved的Promise,它的后续then回调(打印4的那个)会直接加入当前微任务队列。
- 先执行第一个
微任务队列的执行顺序
当前微任务队列里现在有打印4的回调,执行它 → 输出4。当前微任务队列清空后,事件循环检查到新的微任务队列里有打印2的回调,执行它 → 输出2。
所以最终输出顺序是:Out → 4 → 2。
内容的提问来源于stack exchange,提问作者Shiva Ganesh
相关产品推荐
相关产品推荐

