JavaScript异步任务执行顺序:Promise与setTimeout代码输出分析
JavaScript代码执行顺序解析
代码示例
function job(){ sequenceB() sequenceC() } function sequenceB(){ setTimeout(_ => console.log(`🍅 Timeout at B`), 0); Promise.resolve().then(_ => console.log('🍍 Promise at B')); } function sequenceC(){ setTimeout(_ => console.log(`🍅 Timeout at C`), 0); Promise.resolve().then(_ => setTimeout(console.log('🍍 Promise at C'), 1000)); } job();
实际输出顺序
🍍 Promise at B → 🍍 Promise at C → 🍅 Timeout at B → 🍅 Timeout at C
执行逻辑说明
JavaScript的执行依赖事件循环机制,任务分为两类,优先级有明确差异:
- 宏任务:包括setTimeout、setInterval、I/O操作等,任务队列中的宏任务会按顺序执行,每次执行完一个宏任务后会先清空所有微任务。
- 微任务:包括Promise的then/catch/finally回调等,优先级高于宏任务,当前宏任务执行完毕后会立即处理所有微任务。
具体执行步骤:
同步代码执行阶段
- 调用
job(),先执行sequenceB():- 调用
setTimeout,将回调_ => console.log('🍅 Timeout at B')加入宏任务队列。 - 调用
Promise.resolve(),将then的回调_ => console.log('🍍 Promise at B')加入微任务队列。
- 调用
- 接着执行
sequenceC():- 调用
setTimeout,将回调_ => console.log('🍅 Timeout at C')加入宏任务队列。 - 调用
Promise.resolve(),将then的回调_ => setTimeout(console.log('🍍 Promise at C'), 1000)加入微任务队列。
- 调用
- 调用
微任务处理阶段
- 同步代码执行完后,优先处理微任务队列:
- 第一个微任务:执行
sequenceB的then回调,直接输出🍍 Promise at B。 - 第二个微任务:执行
sequenceC的then回调,这里注意:setTimeout的第一个参数是console.log('🍍 Promise at C'),这是立即执行的函数调用(而非延迟执行的回调),所以直接输出🍍 Promise at C,后续生成的无意义回调(console.log返回undefined)不会产生额外输出。
- 第一个微任务:执行
- 同步代码执行完后,优先处理微任务队列:
宏任务处理阶段
- 微任务队列清空后,开始处理宏任务队列:
- 第一个宏任务:执行
sequenceB的setTimeout回调,输出🍅 Timeout at B。 - 第二个宏任务:执行
sequenceC的setTimeout回调,输出🍅 Timeout at C。
- 第一个宏任务:执行
- 微任务队列清空后,开始处理宏任务队列:
内容的提问来源于stack exchange,提问作者Ephraim XYZ
相关产品推荐
相关产品推荐

