前言
很多人学完同步、异步、Promise 之后,还是会对执行顺序感到困惑。
比如:
-
为什么
Promise.then比setTimeout先执行? -
async/await到底算同步还是异步? -
宏任务和微任务到底怎么执行?
这些问题都和 事件循环(Event Loop) 有关。
一、JavaScript的主线程是单线程的
JavaScript 主线程同一时间只能执行一件事。
为了不让耗时任务阻塞主线程,运行环境提供了异步机制。
二、几个核心概念
1)调用栈(Call Stack)
执行同步代码。
2)宏任务队列(Macrotask Queue)
如:
setTimeoutsetInterval- DOM 事件
3)微任务队列(Microtask Queue)
如:
Promise.thencatchfinallyqueueMicrotask
三、执行规则
事件循环大致流程:
- 执行同步代码
- 同步代码执行完后,清空微任务队列
- 执行一个宏任务
- 再清空微任务
- 不断循环
四、经典例子
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是微任务 -
setTimeout是宏任务 -
同步结束后先执行微任务,再执行宏任务
五、async/await 和事件循环
async function test() {
console.log('a');
await Promise.resolve();
console.log('b');
}
console.log('1');
test();
console.log('2');
输出:
1
a
2
b
原因:
-
await前面的代码同步执行 -
await后面的代码相当于放入微任务
六、总结
事件循环的核心记住一句话:
同步代码先执行,微任务优先于宏任务。