0
点赞
收藏
分享

微信扫一扫

理解 JS 中的 EventLoop 事件循环(详细图文教程)


概念

JavaScript 是一门 ​单线程​ 语言,即同一时间只能执行一个任务,即代码执行是同步并且阻塞的。


eg. 这就像只有一个窗口的银行,客户需要一个一个排队办理业务。


只能同步执行肯定是有问题的,所以 JS 有了一个用来实现异步的函数:​​setTimeout​

下面要讲的 Event Loop 就是为了确保 异步代码 可以在 同步代码 执行后继续执行的。

由于涉及到的相关概念较多,我们先从最简单的来。

队列(Queue)

队列​ 是一种 FIFO(First In, First Out) 的数据结构,它的特点就是 ​先进先出


eg. 生活中最常见的例子就是排队啦,排在队伍最前面的人最先被提供服务。


栈(Stack)

​ 是一种 LIFO(Last In, First Out)的数据结构,特点即 ​后进先出​。


eg. 大家都吃过桶装薯片吧~薯片在包装的时候只能从顶部放入,而吃的时候也只能从顶部拿出,这就叫后进先出哈


调用栈(Call Stack)

栈我们已经知道了,那么什么是 ​调用栈​ 呢 ?它里面装的东西,是一个个待执行的函数。

Event Loop 会一直检查 Call Stack 中是否有函数需要执行,如果有,就从栈顶依次执行。同时,如果执行的过程中发现其他函数,继续入栈然后执行。

先拿两个函数来说:

  • 栈空
  • 现在执行到一个​函数A​,函数A​入栈
  • 函数A 又调用了​函数B​,函数B​入栈
  • 函数B​执行完后​出栈
  • 然后继续执行​函数A​,执行完后A也​出栈
  • 栈空

更复杂一点的话,来看一段代码:

理解 JS 中的 EventLoop 事件循环(详细图文教程)_入栈

这段代码在 调用栈中的运行顺序如下图:

理解 JS 中的 EventLoop 事件循环(详细图文教程)_调用栈_02


这个调用栈其实大家经常会见到,就是在控制台报错的时候,错误信息显示的就是当前时刻调用栈的状态。


上面我们讨论的其实都是同步代码,代码在运行的时候只用 调用栈 解释就可以了。

那么,假如我们发起了一个网络请求(request),或者设置了一个定时器延时(setTimeout),一段时间后的代码(回调函数)肯定不是直接被加到调用栈吧?

这时就要引出 ​事件表格(Event Table)​ 和 ​事件队列 (Event Queue)​ 了

Event Table

Event Table 可以理解成一张 ​​事件 -> 回调函数​​ 对应表


它就是用来存储 JavaScript 中的异步事件 (request, setTimeout, IO等) 及其对应的回调函数的列表


Event Queue

Event Queue 简单理解就是 ​​回调函数 队列​​,所以它也叫 Callback Queue


当 Event Table 中的事件被触发,事件对应的 回调函数 就会被 push 进这个 Event Queue,然后等待被执行


Event Loop

先来看一个流程图:

理解 JS 中的 EventLoop 事件循环(详细图文教程)_调用栈_03

  • 开始,任务先进入 Call Stack
  • 同步任务直接在栈中等待被执行,异步任务从 Call Stack 移入到 Event Table 注册
  • 当对应的事件触发(或延迟到指定时间),Event Table 会将事件回调函数移入 Event Queue 等待
  • 当 Call Stack 中没有任务,就从 Event Queue 中拿出一个任务放入 Call Stack

而 ​Event Loop​ 指的就是这一整个圈圈:


它不停检查 Call Stack 中是否有任务(也叫栈帧)需要执行,如果没有,就检查 Event Queue,从中弹出一个任务,放入 Call Stack 中,如此往复循环。


一张更经典的图:

理解 JS 中的 EventLoop 事件循环(详细图文教程)_入栈_04


举报

相关推荐

0 条评论