当前位置: 首页 > 后端技术 > Node.js

Node.js事件循环完整指南

时间:2023-04-03 14:41:43 Node.js

作者:PieroBorrelli使用Node.js时,会出现很多关于它到底是什么、这项技术有什么用处以及它的未来的问题。让我们尝试解决第一部分。回答这个问题最简单的方法是列出Node的一些技术定义:Node.js是构建在Chrome的V8JavaScript引擎之上的Javascript运行环境。Node.js使用事件驱动、非阻塞I/O模型,使其轻量且高效。Node包生态系统(npm)是世界上最大的开源库生态系统。但是,这些答案并不令我满意,因为缺少了一些东西。看完以上几点,你可能会认为Node.js只是另一种JavaScript技术,但要想真正理解它,最重要的还是要分析它是如何进行异步操作的,以及它的非阻塞I/OO系统。这是每个Web开发人员都应该知道的。准确了解Node在幕后是如何工作的,不仅会让您更多地了解这项技术,而且还会激发那些刚刚起步但尚未深入使用它的人的兴趣。对于已经在该领域的专业人士来说,了解它的来龙去脉将使你成为一个新的、尖端的开发人员,可以根据你的需要改进它的性能。因此,为了深入了解Node的世界,我们将研究它的核心部分:事件循环,它实际上是负责其非阻塞I/O模型的部分。对线程的简要回顾在深入研究事件循环之前,我想花一些时间在线程上。如果你想知道为什么这是必要的,我会告诉你,为了更好地理解一个概念,我们必须首先在脑海中形成一个词汇表,这将帮助我们识别系统的每个部分。当我们稍后阅读事件循环的工作原理以及线程的概念如何应用于它时,这将成为一个很大的优势。每当我们运行一个程序时,都会为它创建一个实例,并且有一些内部调用线程与该实例相关联。线程可以被认为是我们的CPU必须执行的操作单元。许多不同的线程可以与程序的单个进程相关联。这里有一张图片可以帮助您在脑海中理解这个想法:线程的简化图讨论线程时最重要的一点是:我们的机器如何确定何时处理哪个线程?众所周知,我们机器的资源是有限的(CPU、RAM),因此正确决定如何分配它们非常重要,换句话说,哪些操作优先于其他操作。这必须在确保操作不会消耗太多时间的同时完成-没有人喜欢慢速计算机。用于解决分配问题的机制称为调度,由操作系统中的调度程序管理。这背后的逻辑可能相当复杂,但总而言之,我们可以结合两种主要方式来做到这一点:多核机器:将不同的线程分配给不同的内核。多核机器如何处理线程使用减少空闲时间的优化逻辑:这是最实用的方法。如果我们仔细看看线程是如何工作的,我们会发现操作系统调度程序可以识别出CPU何时正在等待其他资源来执行作业,因此可以分配它来同时执行其他操作。这通常发生在非常昂贵的I/O操作中,例如从硬盘读取数据。事件循环现在我们对线程的工作原理有了基本的了解,让我们来处理Node.js事件循环逻辑。通过这篇文章,你会明白前面解释背后的原因,每一个都会对应到正确的位置。每当运行Node程序时,都会自动创建一个线程。这个线程是整个代码执行的唯一地方。在它内部产生了一种叫做事件循环的东西。这个循环的作用是安排我们唯一的线程应该在什么时间点执行哪些操作。详解下面我们来尝试模拟一下事件循环是如何工作的以及它是如何工作的。让我们首先假设我们向Node提供一个名为myProgram的文件,然后更详细地了解事件循环将如何处理它。特别是,我将首先用一个简短的图表来解释在事件循环滴答期间发生的事情,然后以更深入的方式探索这些阶段。第一步:performChecks不要简单的认为事件循环其实就是一个循环。它有一个特定的条件来确定循环是否需要再次迭代。事件循环的每次迭代称为一个滴答。事件循环执行tick的条件是什么?每当我们执行一个程序时,我们都有一系列的操作需要执行。这些操作主要分为三种:等待定时器操作(setTimeout(),setInterval(),setImmediate())等待正在进行的操作系统任务等待长时间运行的操作我会在后面详细描述这些;现在让我们记住,只要其中一个操作未决,事件循环就会执行一个新的滴答。第2步:执行一个tick对于每个循环迭代,它可以分为以下几个阶段:第1阶段:Node查看其内部的待定计时器集合,并检查传递给setTimeout()和setInterval()的回调函数是否准备好在定时器到期时调用。阶段2:Node查看其内部挂起的OS任务集合,并检查哪些回调函数已准备好调用。一个例子是从机器的硬盘驱动器中检索文件。阶段3:节点暂停执行,等待新事件发生。新事件包括:新定时器完成、新OS任务完成、新挂起操作完成。阶段4:Node检查是否准备好调用与setImmediate()函数相关的函数。Phase5:管理关机事件,用于清理程序状态。关于事件循环的常见问题和误解Node.js是完全单线程的吗?这是对Node.js的一个非常普遍的误解。Node运行在单线程上,但Node.js标准库中包含的一些函数(例如fs模块函数)不是,它们的逻辑运行在Node.js线程之外。这样做是为了保证程序的速度和性能。这些其他线程在哪里运行?Node.js使用一个名为libuv的特殊库模块来执行异步操作。该库还与Node的后台逻辑一起使用,以管理一个称为libuv线程池的特殊线程池。该线程池由四个线程组成,用于委托对事件循环而言过于繁重的操作。长时间运行的任务对于事件循环来说成本太高。那么事件循环是一个类似栈的结构?从这个意义上说,虽然上述过程中涉及到一些类似栈的结构,但更准确的答案是,事件循环由一系列阶段组成,每个阶段都有自己特定的任务,全部以循环的方式重复处理。如果您想了解更多关于事件循环的确切结构,请查看此演讲。结论了解事件循环是使用Node.js的重要部分,无论您是想更深入地了解这项技术、了解如何提高其性能,还是想找个理由学习新工具。