深刻解析Node.js事件循环工做机制


深刻解析Node.js事件循环工做机制


image.png



做者 | Piero Borrelli
译者 | 张兰月编辑 | 张之栋,Yonie
本文从对线程、事件循环、事件循环常见的问题和错误上分别进行说明,进一步探索了 Node 的核心工做原理。

每当人们谈论 Node.js 时,都会出现不少问题,好比它到底是什么、这项技术有什么用、它是否有将来等等。node

让咱们尝试讨论第一部分。回答这个问题最简单的方法是列出 Node 在技术上的许多定义,如: 
  • Node.js 是一个基于 Chrome V8 JavaScript 引擎构建的 Javascript 运行时环境。
  • Node.js 使用事件驱动的非阻塞 I/O 模型,这使其轻量且高效。
  • Node 包生态系统 (npm) 是全世界最大的开源库生态系统。

可是,这些答案并不能令我彻底满意,由于缺乏一些东西。在阅读上面的要点后,你可能会认为 Node.js 只是另外一种 JavaScript 技术,但理解它最重要的方法是分析它是如何实现异步并具备彻底非阻塞 I/O 系统的。npm

这才是为何它能成为每一个 Web 开发人员必备之物的真正缘由。异步

准确了解 Node 如何在幕后工做不只能增进对这项技术的更多了解,并且还会吸引那些还未用过它的人认识并开始学习它。ide

而对于那些已是该领域专业人士的人来讲,了解 Node 的内部和外部将使你成为一名最新和最前沿的开发人员,而且可以根据自身的需求提升 Node 的性能。函数

所以,为了深刻了解 Node ,咱们将解析其核心部分——事件循环的工做机制。事实上,事件循环就是负责 Node 非阻塞 I/O 模型的部分。工具

刷新对线程的认知

在深刻了解事件循环以前,我想花些时间在线程上。若是你想知道为何这很必要,我会告诉你,为了更好地理解一个概念,咱们必须首先开始在脑海中造成一个词汇表,它将有助于咱们识别系统的每一个部分。这样,在稍后阅读有关事件循环、事件循环如何工做以及线程的概念如何应用在事件循环中的内容时,你才会有很大的优点。oop

每当咱们运行一个程序时,咱们都会建立一个它的实例,而且咱们会调用一些内部线程,他们是与该实例相关联的。线程能够看做是 CPU 必须执行的操做单元。许多不一样的线程能够与程序的单个进程相关联。如下是一个图形,它能够帮助你在脑海中造成这个概念:image.png性能

线程的简单图形学习

在谈论线程时,最重要的一点是 :计算机在某个时刻应该处理哪一个线程?优化

众所周知,咱们的机器资源(CPU、RAM)是有限的,所以正确分配资源很是重要,或者说,哪些操做应该优先执行。这一切都必须实现,并且同时,须要确保全部操做不能耗费太多时间,由于没有人喜欢笔记本电脑速度过慢。

用于解决资源分配问题的机制就叫做调度,它由咱们的操做系统中称为 OS 调度程序的实体来管理。这背后的逻辑可能很是复杂,但总而言之,咱们能够将执行此操做的两大方法组合在一块儿:
  • 多核机器 为不一样的核分配不一样的线程。

  • image.png

多核机器如何处理线程

  • 使用优化逻辑,以减小死锁:这是对咱们来讲最切实的方法。若是咱们仔细研究一下线程是如何工做的,咱们将看到操做系统调度器能够识别出CPU在什么时候等待其余资源来执行一个做业,所以它能够被分配来同时执行其余操做。这一般发生在很是繁重的 I/O 操做上,例如硬盘读取。

事件循环

如今咱们已经对线程的工做原理有了新的了解,咱们终于能够解决Node.js 事件循环逻辑了。经过阅读本文,你会了解前面的解释它背后的缘由,并且每一个部分都会自行找到正确的位置。

每当咱们运行 Node 程序时,都会自动建立一个线程。这个线程就是咱们整个代码库被执行的惟一地方。其中,还生成了一个称为事件循环的东西。这个循环的做用是安排咱们惟一的线程在某个给定的时间点应该执行哪些操做。image.png

请注意:在咱们运行程序后那一刹那,事件循环不会马上生成。实际上,只有在整个程序执行完毕后事件循环才会运行。

详情

如今让咱们尝试模拟事件循环的工做原理以及它如何使咱们的程序开始工做。为此,我将伪装本身正在使用一个名为 myProgram 的文件为 Node 提供信息,而后咱们再详细了解事件循环将执行的全部操做。

特别的,我将首先编写一个简短的图形解释,来讲明在某个事件循环 tick 过程当中发生了什么,而后我将以更深刻的方式探讨这些阶段。image.png

事件循环的图形说明

 第1步:performChecks

我不该该告诉你事件循环其实是一个循环。这意味着它有一个特定的条件,这个条件将决定循环是否须要再次迭代。事件循环的每次迭代都称为 tick

事件循环执行 tick 的条件是什么?

每当咱们执行程序时,咱们都会有一系列须要执行的操做。这些操做可分为三个大类:

  • 挂起的定时器操做 (setTimeout(), setInterval(),setImmediate())。
  • 挂起的操做系统 (OS) 任务。
  • 挂起的长时间运行操做的执行。

咱们稍后会详细介绍这些内容;如今,让咱们记住,只要其中一个操做处于挂起状态,事件循环就会执行一个新的 tick。

第2步:执行 tick

对于每一个循环迭代,咱们能够将其分为如下阶段:
  • 阶段 1:Node 查看挂起的计时器的内部集合,并检查传递给setTimeout()和setInterval()的回调函数是否准备好在计时器过时的状况下被调用。
  • 阶段 2:Node 查看挂起的 OS 任务的内部集合,并检查哪些回调函数已准备好被调用。从计算机的硬盘驱动器中检索文件便是一个例子。
  • 阶段 3:Node 暂停执行,等待新事件的出现。新事件包括:新的计时器完成、新的 OS 任务完成和新的挂起操做完成。
  • 阶段 4:Node 检查是否准备好调用与挂起定时器(挂起定时器与setImmediate()函数相关)相关的任何函数。
  • 阶段 5:管理关闭事件,用于清理应用程序的状态。

常见问题和错误认知  Node.js 是彻底单线程的吗?

这是对这项技术的一种很是广泛的误解。虽然 Node 是在单个线程上运行,可是 Node.js 标准库中包含的有些函数并非如此(例如 fs 模块函数);它们的逻辑运行在 Node.js 单线程以外,这样作是为了保持程序的速度和性能。

  这些其余线程在哪里外包?

使用 Node.js 时,会使用一个名为 libuv 的特殊库模块来执行异步操做。此库还与 Node 的后向逻辑一块儿被用来管理称为 libuv 线程池 的特殊线程池。

此线程池由四个线程组成,它们负责委派对事件循环来讲太繁重的操做。

  那么事件循环是一种相似堆栈的结构吗?

从这个意义上说,虽然在上述过程当中涉及到了一些相似堆栈的结构,但更准确的答案是事件循环由一系列阶段组成,每一个阶段都有本身的特定任务,并且全部阶段都以循环重复的方式被处理。有关事件循环的更多信息,请看这个对话: https://www.youtube.com/watch?v=PNa9OMajw9w。

  结论  

了解事件循环是使用 Node.js 的重要部分,不管你是想得到有关此技术更多看法、了解如何提升其性能,仍是但愿找到学习一个新工具的理由,本文都会对你有所帮助。

英文原文: https://blog.logrocket.com/a-complete-guide-to-the-node-js-event-loop/  

相关文章
相关标签/搜索