JavaScript事件循环先执行同步代码,再清空所有微任务,最后执行一个宏任务,循环往复;同步代码属首个宏任务,Promise.then等为微任务,setTimeout等为宏任务,微任务总在宏任务间“插队”并全部执行完。

JavaScript 的事件循环(Event Loop)是它实现异步非阻塞的关键机制。核心就一条:同步代码先执行,执行完立刻清空所有微任务,再取一个宏任务执行,如此反复。
同步代码是第一个宏任务
整个 script 标签本身就是一个宏任务,也是事件循环的起点。所有同步语句按顺序执行,遇到 setTimeout、setInterval 这类,就进宏任务队列;遇到 Promise.then、queueMicrotask,就进微任务队列。
- 同步代码不等待,直接压栈运行
- 宏任务和微任务不会打断当前同步执行
- 哪怕 setTimeout 设为 0,也得等当前宏任务彻底结束才可能执行
微任务总在宏任务之间“插队”
每当一个宏任务执行完毕,调用栈清空,引擎不做任何延迟,立即检查微任务队列,并把里面所有任务依次执行完——包括执行过程中新产生的微任务(比如在 then 里又 new 了一个 Promise),也会被追加到当前轮次的队尾并执行。
- 微任务没有“下一个”,只有“本轮全部执行完”
- 常见的微任务:Promise 回调、MutationObserver、queueMicrotask
- Node.js 中 process.nextTick 优先级比 Promise.then 还高,但只在 Node 环境有效
宏任务按队列顺序逐个取出
微任务队列清空后,事件循环才从宏任务队列头部取一个任务执行。这个过程不是“批量处理”,而是每次只拿一个,执行完再回来清微任务,再拿下一个。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 常见宏任务:setTimeout/setInterval、I/O 回调、UI 渲染(浏览器)、script 全局代码、requestAnimationFrame
- 即使两个 setTimeout 都设为 0,它们仍按注册顺序排队,不会同时触发
- 浏览器在每次宏任务后可能插入一次 UI 渲染(不是每次必渲染,取决于是否需要更新)
典型执行顺序示例
看这段代码:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
输出是:1 → 4 → 3 → 2。
原因:1 和 4 是同步代码,立刻输出;然后清微任务,执行 Promise.then 输出 3;最后取宏任务,执行 setTimeout 输出 2。

















