最直观的 JavaScript Event Loop 动画演示
JavaScript 是一门单线程的语言,它的异步和多线程的实现是通过 Event Loop 事件循环机制来实现的。Event Loop 包括三个概念:调用栈(call stack)、消息队列(Message Queue)和微任务队列(Microtask Queue)。
调用栈 (call stack)
Event Loop 开始时,会从全局代码开始,一行一行执行,遇到函数调用时,会把函数压入调用栈中(被压入的函数叫做帧(frame)
,当函数返回后,会从调用栈中弹出。例如:
// 2, 1, 3
function func1() {
console.log(1);
}
function func2() {
console.log(2);
func1();
console.log(3);
}
func2();
此段代码执行时:
- 首先把 fun2() 压入调用栈中,然后执行它里边的代码,- 把
console.log(2)
压入栈中并执行,执行完毕打印出2
后弹出。 - 接下来把
func1()
的调用压入栈中,执行它里边的代码,console.log(1)
被压入栈,执行并打印出1
,弹出。 - 然后
func1()
执行完毕,弹出。 - 最后
console.log(3)
压入栈中,执行并打印出3
,弹出。
整个调用栈被清空。
消息队列 (Message Queue)
JavaScript 中的异步操作比如(fetch)、事件回调、setTimeout、setInterval 的回调函数会入队到消息队列中,它们叫做消息。例如,在上边的代码中加上 setTimeout 的调用:
// 1, 3, 2
function func1() {
console.log(1);
}
function func2() {
setTimeout(() => {
console.log(2);
}, 0);
func1();
console.log(3);
}
func2();
这里在 setTimeout
被压入栈时,它里边的回调函数(匿名函数)会入队到消息队列中,它里边的消息会在调用栈清空的时候执行(这也是为什么 setTimeout 中的延迟参数只是最小延迟时间)。接下来当console.log(3)
执行完毕之后,调用栈为空,消息队列中的消息会压入到调用栈中并执行,最后打印出2
。
微任务队列 (Microtask Queue)
使用 Promise、Async/Await 创建的异步操作会入队到微任务队列中,它也会在调用栈被清空的时候执行,比消息队列优先级高,例如在上边的代码中加入 promise 的定义:
var p = new Promise((resolve) => {
console.log(4);
resolve(5);
});
function func1() {
console.log(1);
}
function func2() {
setTimeout(() => {
console.log(2);
});
func1();
console.log(3);
p.then((resolved) => console.log(resolved));
}
func2();
- Promise 构造函数被压入调用栈,之后
console.log(4)
和resolve(5)
分别压入栈中并 执行。最后promie
构造函数会弹出。 - 下边的执行过程和上边的例子一样,调用 func2(),setTimeout 中的匿名回调入队到消息队列中,调用
func1()
打印出1
,然后打印3
,在遇到then
的时候,传给then
的回调函数会入队到微任务队列中,此时调用栈为空,所以执行微任务队列中的任务,把回调压入调用栈并执行,打印出 5,最后压入并执行消息队列中的消息,打印出5
。
一系列的课程让你成为高级前端工程师。课程覆盖工作中所有常用的知识点和背后的使用逻辑,示例全部 都为工作项目简化而来,学完即可直接上手开发!
即使你已经是高级前端工程师,在课程里也可能会发现新的知识点和技巧,让你的工作更加轻松!
《React 完全指南》课程,连载中现只需 48 元(领取优惠券)点击查看详情。
《Vue 3.x 全家桶完全指南与实战》课程,包括 Vue 3.x、TypeScript、Vue Router 4.x、Vuex 4.x 所有初级到高级的语法特性详解,让你完全胜任 Vue 前端开发的工作。点击查看详情。
《React即时通信UI实战》课程,利用 Storybook、Styled-components、React-Spring 打造属于自己的组件库。
《JavaScript 基础语法详解》本人所著图书,包含 JavaScript 全面的语法知识和新特性, 可在京东、当当、淘宝等各大电商购买