再话js的事件循环机制

238 阅读4分钟

前言

    众所周知,JS是一门单线程语言,那我们在开发过程中实现的那些异步操作它又是如何做到的呢。答案是:Event Loop。那么在JS内部有着怎样的一套运行机制呢,下面我们通过一张图来说明这一点。

    该图引用自Philip Roberts的演讲 《Help, I'm stuck in an event-loop》,图中涉及到了Heap、Stack、Event Loop 和Queue,我们依次来理解一下:

1. Heap:堆。是线性数据结构,相当于一维数组,是一种动态存储的结构。在js中,Heap是动态分配的内存也就是存储代码块,大小不定,也不会自动被释放,保存指向对象的指针。其作用是为了存储引用类型值的数据。

let person = {         
    name: 'Jessica',        
    age: 28,        
};    

                                             

2. Stack:栈。在JS中, Stack确切来说是调用栈,它会自动分配内存和自动释放占据固定大小的空间,其作用主要是:存放基本类型和简单的数据段,如:string, number, boolean等等;提供代码的执行环境。

                                             

可以看出:0x01这个内存地址所指向的位置就是person对象的存放位置。

栈也是一种数据结构,先送只能再表尾进行插入/删除操作的特殊线性表,它按照后进先出(last-in-first-out: LIFO)的规则存储数据。

3. Queue:队列。队列也是一种数据结构,它允许再队头进行删除操作,队尾进行插入操作,与栈类似,当队列中没有元素是,该队列就是空队列。它的这种操作特性可以看出来,满足先进先出(first-in-first-out: FIFO)规则。

4. Event Loop (事件循环)

    为什么会出现事件循环呢,这个问题是因为js本身是单线程且非阻塞的,非阻塞的实现使用了异步编程,而Event Loop就是为了解决异步编程而出现的一种解决方案。

    javascript的主要用途是与用户交互,以及操作DOM,如果它是多线程的话,会有很多复杂的问题需要处理。比如说:一个线程删除了DOM节点,但另外一个线程正好处于需要操作这个DOM的阶段,那么到底是以哪个线程的操作为准呢?

    单线程就意味着,所有的任务都需要排队,前一个任务结束之后才会执行下一个任务。如果前一个任务耗时很长,那后面的任务就不得不一直等待。js引擎执行异步任务就不需要一直等待而造成浪费。

1.事件循环Event Loop

    知道了基本的概念之后,我们再来详细的看一看Event Loop.

1.1 浏览器中的Event Loop执行顺序

    只要存在Event Loop,就会不断的按照下面的步骤执行:

  1. 在任务队列Task Queue(宏任务)中选择一个最老的task,如果没有可以选择的任务,就继续执行下面的microtasks任务;
  2. 将1中的task设置为正在运行的task;
  3. 执行被选择的task;
  4. 将Event Loop中的当前运行任务变为空,并移除已经运行的task;
  5. 执行microtasks任务队列中的任务,更新浏览器渲染;
  6. 返回第一步循环。

总结起来就是:Event Loop会循环不断的去拿宏任务队列中最老的一个任务,推入栈中执行,并在当次循环里一次执行并清空microtask队列里的任务,执行完microtask队列里的任务之后,更新渲染。

1.2 宏任务与微任务

这两种任务都是在任务队列的异步事件中注册的回调函数。宏任务可以有多个,但微任务只有一个。

宏任务:macrotasks

(1) setTimeout()/setInterval()

(2) UI渲染

(3) 包起来的代码块

(4) I/O

(5) ... ...

微任务:microtasks

(1) Promise的then(), catch(), finally()

(2) process.nextTick()

(3) MutationObserver

两种任务的执行过程总结如下图所示:

所以对于Event Loop的执行过程而言,宏任务优先,在执行完宏任务之后才会一次性执行完任务队列中的所有微任务。

附录

  1. 文中所有的图片都是采用在线画图工具:diagrams,它可以与github关联,将平时画的图保存在自己的库中,同时也支持修改。
  2. 参考文章:

(1)大神1:juejin.cn/post/686884…,知识扩展非常全面,我也是通过这篇文章才萌生出要整理一下JS事件循环机制的想法。

(2)大神2:juejin.cn/post/684490…