javascript事件循环执行顺序为宏任务→微任务→渲染→下一轮宏任务;宏任务含settimeout等,微任务含promise.then等;每轮宏任务后清空全部微任务队列,再进行渲染或下一轮宏任务。

JavaScript 是单线程语言,靠事件循环(Event Loop)协调同步代码与异步任务的执行顺序。理解它,关键不是背概念,而是看清“宏任务→微任务→渲染→下一轮宏任务”这个实际流转链条。
宏任务和微任务的层级关系决定执行优先级
宏任务(Macrotask)包括:整体脚本、setTimeout、setInterval、I/O、UI 渲染等;微任务(Microtask)包括:Promise.then/catch/finally、queueMicrotask、MutationObserver回调等。
每次宏任务执行完,引擎会清空当前所有微任务队列,再进入下一个宏任务——这是异步逻辑“看似并行”却严格有序的核心机制。
- 一个 setTimeout 回调是宏任务,会排到下一轮事件循环才执行
- 一个 Promise.resolve().then(...) 是微任务,会紧接在当前宏任务末尾执行,不等渲染或下一个定时器
- 连续多个 then 会按顺序压入微任务队列,依次执行,中间不插其他宏任务
从代码执行流程看事件循环的实际步骤
以一段典型混合代码为例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); console.log(4);
执行过程如下:
- 同步代码逐行执行:输出 1 → 注册 setTimeout(宏任务)→ 注册 Promise.then(微任务)→ 输出 4
- 第一轮宏任务结束,立即执行全部微任务:输出 3
- 浏览器进行可选的 UI 渲染(此处无变化)
- 取出下一个宏任务(setTimeout 回调),执行:输出 2
注意几个易混淆的实际细节
事件循环不是“每毫秒检查一次”,而是在每个宏任务结束后主动检查微任务队列,并在必要时触发渲染。真实行为还受浏览器优化影响:
- setTimeout(fn, 0) 不代表立刻执行,只是尽快安排进下一轮宏任务,实际延迟通常 ≥ 4ms(HTML 规范限制)
- Promise 链中的错误不会跳过后续 then,除非显式 catch;未捕获的 reject 会作为微任务在本轮末尾抛出(但不中断当前微任务流)
- await 实际是语法糖,它把 await 后面的值转为 Promise,然后将 await 后代码包装成微任务,所以 await Promise.resolve() 后的语句属于下一个微任务
调试技巧:用 queueMicrotask 和 performance.now 辅助观察
想验证某段逻辑是否在微任务中执行,可用 queueMicrotask 手动插入对比点:
console.log('sync');
setTimeout(() => console.log('macro'), 0);
queueMicrotask(() => console.log('micro'));
// 输出顺序一定是:sync → micro → macro
配合 performance.now() 可粗略测量任务排队延迟,比如比较两个 setTimeout(0) 与两个 queueMicrotask 的时间差,能直观看到微任务更快响应。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










