为何调用栈空闲时异步代码仍未执行?JS异步机制疑问
JavaScript异步执行的核心:宏任务与微任务
你遗漏了JavaScript事件循环中微任务和宏任务的优先级差异,以及同步代码执行的绝对优先级。我们一步步拆解代码执行流程,就能明白输出顺序的原因:
先明确两个关键概念
- 同步代码:直接进入调用栈按顺序执行,执行完之前不会处理任何异步任务。
- 异步任务分两类:
- 微任务:优先级高,包含Promise的
then/catch/finally、MutationObserver等。 - 宏任务:优先级低,包含
setTimeout、setInterval、DOM事件、AJAX请求等。
- 微任务:优先级高,包含Promise的
代码执行全流程
- 执行
console.log('test start');,输出test start(你的实际输出可能遗漏了这行,但代码逻辑中存在)。 - 调用
setTimeout(...):作为宏任务,回调函数被放入宏任务队列等待后续处理。 - 调用
Promise.resolve(...).then(...):Promise的then回调是微任务,被放入微任务队列。 - 执行两次
fu():属于同步代码,直接进入调用栈执行,输出两次after 1,执行完后回到全局代码。 - 执行
console.log('Test End');:仍是同步代码,输出Test End,此时全局同步代码全部执行完毕,调用栈为空。
你标记的位置处于两次fu()之后、console.log('Test End');之前,此时调用栈并未完全清空——全局代码还剩最后一行未执行,所以异步任务根本没到执行时机。
异步任务的执行时机
当调用栈彻底清空后,事件循环会遵循以下顺序处理异步任务:
- 先清空所有微任务队列:取出Promise回调执行,输出
Resolve promise1。 - 微任务队列处理完毕后,再处理宏任务队列:取出
setTimeout回调执行,输出0 sec timer。
核心规则总结
- 同步代码永远优先执行,必须等当前调用栈内所有同步代码执行完毕,才会处理异步任务。
- 异步任务中微任务优先级高于宏任务,必须等所有微任务执行完毕,才会开始执行宏任务。
内容的提问来源于stack exchange,提问作者MohishKhadse55
相关产品推荐
相关产品推荐

