深入浅出 JavaScript 事件循环:从宏任务到微任务

本文最后更新于:2026年2月11日 晚上

深入浅出 JavaScript 事件循环

JS 是单线程的,意思是他一次只能干一件事。但我们在开发里经常要处理异步:发请求、设定时器、监听点击。这看着挺矛盾的,其实全靠 事件循环 (Event Loop) 在背后调度。

1. 为什么是单线程?

JS 最初设计就是为了在浏览器里操作 DOM。如果它是多线程,那问题就大了:
线程 A 说:“我要删掉这个按钮。”
线程 B 说:“我要给这个按钮改个颜色。”
浏览器该听谁的?为了躲开这种麻烦,JS 选了单线程。但这不代表它只能“傻等”同步任务执行完,事件循环就是为了让它能处理异步。

2. 宏任务与微任务

宏任务 (MacroTask)

通常是一些比较重的任务:

  • setTimeout / setInterval
  • I/O 操作(读文件、网求请求)
  • 整个脚本的初次执行
  • UI 渲染

微任务 (MicroTask)

通常是比较轻、需要赶紧处理的任务:

  • Promise.then() / catch() / finally()
  • queueMicrotask()
  • MutationObserver(监听 DOM 变化)

执行顺序:微任务会“插队”

核心规则只有一条:每执行完一个宏任务,都要去把微任务队列清空,然后再执行下一个宏任务。

看个经典例子:

1
2
3
4
5
6
7
8
9
10
11
console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => {
console.log('3');
});

console.log('4');

// 输出:1 → 4 → 3 → 2

解析一下:

  1. 14 是同步任务,直接输出。
  2. setTimeout 的回调被扔进宏任务队列。
  3. Promise.then 的回调被扔进微任务队列。
  4. 同步代码跑完,JS 发现微任务队列里有 3,赶紧执行它。
  5. 微任务清空了,再去跑宏任务里的 2

async/await 怎么看?

await 后面的代码,其实可以看作是放在 .then() 里的微任务

1
2
3
4
5
6
7
8
async function test() {
console.log('A');
await Promise.resolve();
console.log('B');
}
test();
console.log('C');
// 输出:A → C → B

再看个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function a() {
console.log('a');        
Promise.resolve().then(() => {          
console.log('e');        
});        
Promise.resolve().then(() => {          
console.log('ee');        
});    
}
function b() {console.log('b');}
function c() {
console.log('c');      
Promise.resolve().then(() => {        
console.log('cc');      
});    
}
function d() {        
setTimeout(a, 0);        
Promise.resolve().then(b);        
setTimeout(c, 0);        
console.log('d');    
}    
d();// d b a e ee c cc

执行解析:
    1、遇到第一个setTimeout放入宏任务队列 【a()】
    2、遇到promise 放入 微任务队列 【b()】
    3、遇到第二个setTimeout放入宏任务队列 【a(),c()】
    4、输出:d,主js代码执行完毕
    5、读取微任务队列所有任务,输出 :b
    6、读取宏任务队列,取出第一个【a()】,输出:a,同时放入微任务队列:【e,  ee】
    7、读取微任务队列所有任务,输出 :e    ee
    8、读取宏任务队列,取出第一个【c()】,输出:c,同时放入微任务队列:【cc】
    9、读取微任务队列所有任务,输出 : cc
    10、执行完毕


深入浅出 JavaScript 事件循环:从宏任务到微任务
http://bestkele.com/2020/07/19/concept/eventloop/
作者
kele
发布于
2020年7月19日
许可协议