深圳幻海软件技术有限公司 欢迎您!

​Node.js中的事件循环是如何工作的

2023-02-28

​译者|卢鑫旺当我们启动一个Node.js应用程序时,它会加载事件循环并将必要的回调函数添加到回调栈中。在本文中,你将详细了解Node.js中的事件循环是如何工作的。一、为什么你应该了解Node.js中的事件循环以下几点阐述为什么了解事件循环很重要:理解事件循环的原理有助于你写出更高效的代码当你的应

​译者 | 卢鑫旺

当我们启动一个Node.js应用程序时,它会加载事件循环并将必要的回调函数添加到回调栈中。在本文中,你将详细了解Node.js中的事件循环是如何工作的。

一、为什么你应该了解Node.js中的事件循环

以下几点阐述为什么了解事件循环很重要:

理解事件循环的原理有助于你写出更高效的代码

当你的应用程序出现异常错误时能帮你更容易地调试你的代码

QQ">

二、什么是事件循环

根据Node.js官方网站的说法,事件循环允许Node.js执行非阻塞I/O操作——尽管JavaScript是单线程的——会尽可能地将操作转移到系统内核中。

我们可以把这个定义分解为三个关键字:

  • 非阻塞I/O操作
  • 单线程
  • 系统内核

1.非阻塞I/O操作

如果一个操作的执行没有被阻塞,我们就说这个程序是非阻塞的。既然我们在这里提到了非阻塞,那么我们也应该提到什么是阻塞。它只是意味着你必须在一个操作完成后才能再完成另一个操作。

2.单线程

如果一个程序只有一个调用栈,并且它使用了先进先出的概念,在同一个时刻只能执行一个任务,那么这个程序就是单线程的。这意味着栈上的第一个程序总是在下一个程序之前运行。虽然JavaScript看起来是单线程的语言,不过这只取决于它运行的环境。

3.系统内核

在这里,内核只是指运行程序的操作系统。Javascript是单线程的,但Node.js在执行多个输入输出(I/O)操作时能够不阻塞线程。它通过尽可能将此操作交给操作系统(例如Linux、Windows、Mac OS X等)来实现这一点。操作大多被转移到操作系统中;这就是Javascript与Node.js的区别。

三、Node.js中的事件循环是如何工作的

当我们启动node应用程序时,事件循环立即开始运行。事件循环有多个阶段,每个阶段都有要执行的回调队列。当事件循环被添加到特定阶段时,它将在该特定阶段执行一些操作,然后在该阶段队列中执行一些回调。

这将一直持续到队列为空或已经执行了最大数量的回调函数。当达到限制时,事件循环会进入下一阶段执行相同的操作。

有四个最重要的阶段:

  • 到期时间回调
  • I/O轮询和回调
  • setImmediate回调
  • close回调

1.到期时间回调

该阶段负责处理过期定时器的回调函数。

举例:

setTimeout (()=> console.log ('expired timers'), 1000)
  • 1.

是一个函数,它设置了一个在一定时间后过期的定时器。

因此,如果这个定时器有回调函数的话,那么它们将是事件循环首先处理的函数。

如果计时器稍后到期,在处理其他某个阶段的时间内,则只有当事件循环返回到第一阶段时,才会调用该计时器的回调。它在所有四个阶段都是这样工作的。

2.I/O轮询和回调

轮询基本上意味着搜索准备好处理的新I/O事件,并将其放入回调队列。理解在Node应用程序的上下文中,I/O只是指网络和文件访问之类的事情,这一点至关重要。

举例:

fs.readFile('file.txt', (e, d)) =>

console.log(‘File read’)

})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

在这个阶段,99%的代码都会被执行,因为在典型的Node应用程序中,我们需要做的大部分工作都与网络和读取文件有关。

3.setImmediate回调

如果我们想在轮询和执行阶段的I/O之后立即处理回调,我们使用这个特殊的计时器。这在一些更高级的情况下可能是重要的。

setImmediate(() => setImmediate(() =>

console.log('immediate');

});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

4.close回调

在这个阶段,所有的close关闭事件都会被处理,例如,当一个Web服务器关闭时。这就完成了事件循环的第四个阶段。

注意:Node.js事件循环内部还使用了其他事件,但就本文而言,以上四个事件对我们来说是至关重要的。

如上所述,我们完成了这个过程,这只是事件循环中的一个周期。循环结束后,Node.js决定是继续循环还是退出循环。

Node只是通过检查是否有任务(例如定时器或I/0任务)仍然在后台运行来做到这一点。如果没有,它就会退出应用程序。如果有待处理的任务,它们会继续处理下一个任务,例如处理HTTP请求或读取文件。

这基本上就是Node事件循环的全部内容。

四、避免阻塞事件循环

因为Node.js中的所有内容最终都运行在单个线程中,你可以让数百万用户同时访问同一个池,这使得Nde.js非常轻量级和可扩展。但与此同时,它有阻塞单个线程的危险,这将使整个应用程序变慢,甚至停止应用程序。

五、避免阻塞事件循环的一些准则

作为开发人员,你有责任避免事件循环的阻塞。下面的这些准则可以帮助你避免阻塞事件循环。

  • 不要在回调函数中使用fs、crypto和Zlib模块中函数的同步版本。
  • 处理较大的对象时,使用JSON时要小心。
  • 不要使用过于复杂的正则表达式(例如,嵌套的量词)。
  • 不要在嵌套对象上执行复杂的计算。

六、关于Node.js事件循环的最后思考

事件循环使Node.js中的异步编程成为可能。这使得它成为Node设计中最重要的特性。这使得Node.js与其他平台完全不同。

它负责处理所有传入的事件,并通过将较重的任务转到线程池并自己执行最简单的工作来执行编排。

原文链接:https://hackernoon.com/how-do-event-loops-in-nodejs-work

译者介绍

卢鑫旺,51CTO社区编辑,编程语言爱好者,对数据库,架构,云原生有浓厚兴趣。​