老是被问事件循环,今天终于懂了!

在浏览器中,JavaScript 的执行是单线程的。如何在单线程中实现异步操作呢?答案就是事件循环。

事件循环(Event Loop)

浏览器通过事件循环来处理事件、用户交互、JS 代码执行、渲染、网络请求等。通常又两种事件循环,一种是 Window 事件循环,一种是 Worker 事件循环。由于它们核心的工作原理相同,本文我们仅仅讨论 Window 事件循环。

事件循环,首先是一个循环,每个循环周期会执行一些代码,一个循环周期被称为 tick。

while (eventLoop.waitForTask()) {
  eventLoop.processNextTask()
}

一个事件循环有一到多个任务队列。每个任务队列就是一个有序的任务列表。可以理解为一段要执行的代码,或者浏览器要执行的一个动作,比如发送事件、解析 HTML 等。

网页和浏览器本身的用户界面程序运行在相同的线程中,共享相同的事件循环。 该线程就是主线程,它除了运行网页本身的代码之外,还负责收集和派发用户和其它事件,以及渲染和绘制网页内容等。然后,事件循环会驱动发生在浏览器中与用户交互有关的一切。

执行过程

简略的说,事件循环在每一个循环周期都会顺序执行下面的步骤:
1.选择一个任务队列,从队列中取出最靠前(最老的)的任务。如果已经没有任务了,则跳到第 3 步。
2.执行取出的任务。
3.从微任务(Micro Task)队列中取出微任务执行,知道清空微任务队列。
4.更新渲染(resize、scroll、动画等)
5.返回第 1 步。
每一个时间循环都有一个微任务队列。微任务队列与任务队列很像,不同的地方在于,每次循环周期只会执行任务队列中的一个任务,在这期间产生的任何任务都只能在下一个循环周期中才能得以执行。在执行前任务后,事件循环会一次执行微任务队列中的每一个微任务,直到微任务队列为空。也就是说,在微任务执行过程中新产生的微任务,也会在当前循环周期内得到执行。

不同的任务队列可能有不同的优先级。比如浏览器可能会将用户鼠标和键盘输入(用户交互)的任务都放在一个任务队列中,其他任务放到另外一个队列中。在每个循环周期中优先从用户交互队列中取出任务执行,来保证及时响应用户操作。

下图展示了一个事件循环周期的执行过程。
老是被问事件循环,今天终于懂了!_第1张图片

任务与微任务

一个任务可以简单的理解为一段要执行的 JavaScript 代码。比如当执行

你可能感兴趣的:(老是被问事件循环,今天终于懂了!)