浅析JavaScript事件循环(Event Loop)

我正在参加「掘金·启航计划」

前言

JavaScript是一门单线程脚本语言,这意味着JavaScript中的所有代码都是按照顺序一行一行执行的。

为了处理异步操作,JavaScript引入了事件循环机制(Event Loop)来协调异步操作和同步代码的执行。本文将介绍JavaScript事件循环机制。

JavaScript运行机制

JavaScript引擎在执行JavaScript代码时,会将任务分为两类:同步任务异步任务。同步任务在主线程上执行,而异步任务则由任务队列中的事件循环机制异步执行。在异步任务完成后,就会将该任务对应的回调函数放入任务队列中,并等待主线程执行完当前所有的同步任务后再执行该回调函数。

JavaScript中的回调函数是一种特殊的函数,它作为另一个函数的参数传递进去,在该函数执行完特定的操作后被异步调用。

下面我们就详细介绍一下JavaScript任务循环的机制。

事件循环

事件循环是指不断从任务队列中取出任务,并执行其对应的回调函数的过程。事件循环在JavaScript引擎内部以非常高效的方式运行,在等待异步I/O操作返回数据时,可以将CPU时间释放给其他线程使用。

事件循环的基本流程如下:

  1. 主线程执行同步任务,直到遇到异步任务时,将其回调函数添加到任务队列中,然后继续执行同步任务。
  2. 当所有同步任务执行完成后,主线程会立即去任务队列中查找是否有已经完成的异步任务的回调函数需要执行,如果有,则会按照回调函数添加的先后顺序执行它们。
  3. 执行完所有已经完成的异步任务回调函数后,重复步骤2,直到任务队列中没有任何任务。

任务队列

任务队列是指在JavaScript引擎中用来存储异步任务的队列,任务队列中的每个任务都与一个回调函数相关联。当异步任务执行完成后,JavaScript引擎将相应的回调函数添加到任务队列中,等待主线程执行完当前的同步任务后再执行这些回调函数。

微任务和宏任务

在任务队列中,异步任务被分为微任务和宏任务两种类型。宏任务通常是由事件触发或者定时器设定的,而微任务则是它们的回调函数。

在事件循环的过程中,执行顺序优先处理微任务,只有当微任务队列为空时才会去处理宏任务。这样可以保证微任务能够尽可能快地执行,从而提高了程序的响应性和性能。

浅析JavaScript事件循环(Event Loop)

常见的微任务包括Promise的回调函数、MutationObserver的回调函数等。

常见的宏任务包括定时器任务、I/O任务、UI渲染任务等。

  • 定时器任务(setTimeout、setInterval):当计时器到达设定时间后,将其回调函数添加到任务队列中。
  • I/O任务(包括网络请求、文件读写等):当异步I/O操作完成后,将其回调函数添加到任务队列中。
  • UI渲染任务:当需要更新页面的状态时,将相关的UI操作添加到任务队列中。

示例代码

console.log("Start");

setTimeout(() => {
  console.log("Timeout");
}, 0);

Promise.resolve().then(() => {
  console.log("Promise 1");
}).then(() => {
  console.log("Promise 2");
});

console.log("End");

执行以上代码,我们预期的输出结果应该是:

Start
End
Promise 1
Promise 2
Timeout

分析过程

  • 主线程执行同步代码,输出Start和End。
  • 主线程执行Promise.resolve()方法,将Promise的回调函数添加到微任务队列中。由于Promise的回调函数只是一个简单的console.log语句,执行速度非常快,因此Promise 1和Promise 2的输出结果将出现在Timeout之前。
  • 主线程执行setTimeout函数,将其对应回调函数添加到宏任务队列中。由于定时器的延迟时间设置为0,因此定时器回调函数的执行顺序将靠后,在下一个事件循环中执行。

参考资料

Js 的事件循环(Event Loop)机制以及实例讲解

你不会还没搞懂JS事件循环(Event Loop)吧?

原文链接:https://juejin.cn/post/7242895029957001277 作者:舟羽

(0)
上一篇 2023年6月11日 上午11:07
下一篇 2023年6月12日 上午10:00

相关推荐

发表回复

登录后才能评论