搞懂 JavaScript Event Loop

简介: Event Loop,事件循环,是贯穿 JavaScript 整个执行时的关键,这篇文章将通过理论+实践的方式,带你进一步了解这个神奇的机制。

image.png

作者:UC 国际研发 阿定

Event Loop,事件循环,是贯穿 JavaScript 整个执行时的关键,这篇文章将通过理论+实践的方式,带你进一步了解这个神奇的机制。

理论篇

image.png

(图片来源于 MDN)

上图比较形象地概括了 JavaScript 在运行时的理想情景,下面逐一介绍。

函数调用栈 Stack

Stack,顾名思义,是一个 FILO(First In Last Out) 的结构。每次调用函数,在系统中就会把当前函数以及函数内的变量压栈,举个栗子:
image.png

上面代码,定义了两个函数对象,并且执行了一条语句 test(1),试行时, test 函数入栈,进入到 test 函数的执行上下文,发现 return test2(n),再把 test2 函数入栈,最后 test2 返回结果,test2 函数出栈,test 出栈,输出结果:124。

image.png

堆内存 Heap

堆内存中存放的是对象,即引用类型的变量,保存的是实际的内容,而变量名仍然是保存在上面说的 stack 内存中,所以当我们操作变量名,比如:

image.png

实际上,做的是,在栈内存中声明了一个变量 b,并把 b 指向了 a 所指向的堆内存中的那个对象。

异步队列 Event Queue

因为 JS 单线程的特性,实际上很多需要耗时的任务,JS 都会把异步任务都放到 queue 中,在主线程的事情做完后,会定期的轮询 queue,把里面的结果拿出来,这样循环往复的过程就构成了 Event Loop。

Event Loop

实际上,对于异步任务来说,不是所有的任务的生产都是一样的。这里有两个重要的概念 macrotasks 和 microtasks。这两种 task 占据了不同的 queue(Macro event queue 和 Micro event queue),并且这两种任务不会混在一起执行。为什么呢?因为对于每一轮的 Event Loop 来说,会取出 Macro event queue 中的一个 task 出来执行,完成这个 marcotask 后,会从 Micro event queue 取出所有 microtasks 执行,至此完成一轮 Event Loop。下一循环又重复这个过程。

举个栗子:

image.png

上面一段代码,在引擎解析后完成后,就会变成这样,如图所示:

image.png

1、首先执行同步任务,按出现顺序,输出 1

2、遇到 setTimeout,放入Macro event queue

3、遇到 process,放入 Micro event queue

4、遇到 promise,先立即执行,输出 4,并将 then 回调放入 Micro event queue

5、然后看 Micro event queue,逐个执行,输出 3, 输出 5

6、第一轮 Event Loop 执行结束

然后开始第二轮 Event Loop

image.png

1、取出 Macro event queue 第一个放入主流程执行

2、输出 2

3、Micro event queue 没有任务

4、第二轮 Event Loop 执行结束

Macrotasks & Microtasks

Macro:

setTimeout, setInternal, setImmediate, I/O tasks

Micro:

process.nextTick, Promises

引擎标准

实际上,对于怎么处理 macrotasks 和 microtasks 完全取决于引擎。所以说,同样的代码,在 Chrome 执行的输出效果,也许跟 Firefox, Safari会不一样。

实战篇

image.png

image.png

还是画图辅助:

第一轮 Event Loop:

image.png

1、主流程输出:1, 4, 7

2、执行第一个 Micro event queue:输出 3

3、第二个 Micro event queue:输出 5

4、Micro event queue 清空,第一轮执行完毕

第二轮 Event Loop:

image.png

1、主流程输出 2

2、Micro event queue 为空,第二轮执行完毕

第三轮 Event Loop:

image.png

1、主流程输出 6

2、第二轮执行完毕

第四轮 Event Loop:

image.png

1、注意,这里执行输出 8 后,resolve,这时才向 Micro event queue 压入 then 回调

2、执行 then9 回调,输出 9

3、又有新的 setTimeout,压入 Macro event queue

4、这轮循环没有东西可执行,结束

第五轮 Event Loop:
image.png

1、第五轮,setTimeout10 进入主流程,输出 10

2、遇到 promise,输出 11

3、resolve, 压入 then 到 Micro event queue

4、取出 Micro event queue 执行,输出 12

5、完毕

至此, 这段代码的完整执行流程就结束了,最终输出:

1, 4, 7, 3, 5, 2, 6, 8, 9, 10, 11, 12
目录
相关文章
|
5月前
|
JavaScript 前端开发
JavaScript DOM 操作:什么是事件委托(Event Delegation)?有什么优势?
JavaScript DOM 操作:什么是事件委托(Event Delegation)?有什么优势?
116 1
|
5天前
|
存储 JavaScript 前端开发
深入理解JavaScript中的事件循环(Event Loop):机制与实现
【10月更文挑战第12天】深入理解JavaScript中的事件循环(Event Loop):机制与实现
24 3
|
1月前
|
JavaScript 前端开发 API
详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务
该文章详细讲解了队列数据结构在前端开发中的应用,并深入探讨了JavaScript的事件循环机制,区分了宏任务和微任务的执行顺序及其对前端性能的影响。
|
5天前
|
前端开发 JavaScript
深入理解JavaScript中的事件循环(Event Loop):从原理到实践
【10月更文挑战第12天】 深入理解JavaScript中的事件循环(Event Loop):从原理到实践
16 1
|
1月前
|
存储 JavaScript 前端开发
JavaScript:事件循环机制(EventLoop)
【9月更文挑战第6天】JavaScript:事件循环机制(EventLoop)
29 5
|
2月前
|
JavaScript
Vue.js 中的 $v 和 $event 代表什么?
Vue.js 中的 $v 和 $event 代表什么?
|
3月前
|
JavaScript
js【详解】event loop(事件循环/事件轮询)
js【详解】event loop(事件循环/事件轮询)
46 0
|
3月前
|
JavaScript 前端开发 API
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
42 0
|
5月前
|
JavaScript 前端开发
前端 JS 经典:宏任务、微任务、事件循环(EventLoop)
前端 JS 经典:宏任务、微任务、事件循环(EventLoop)
50 0
|
5月前
|
前端开发 JavaScript
深入理解JavaScript的事件循环(Event Loop)
深入理解JavaScript的事件循环(Event Loop)