写点什么

深入解析 Node.js 事件循环工作机制

  • 2019-08-06
  • 本文字数:2689 字

    阅读完需:约 9 分钟

深入解析Node.js事件循环工作机制

本文从对线程、事件循环、事件循环常见的问题和错误上分别进行说明,进一步探索了 Node 的核心工作原理。


每当人们谈论 Node.js 时,都会出现很多问题,比如它究竟是什么、这项技术有什么用、它是否有未来等等。


让我们尝试讨论第一部分。回答这个问题最简单的方法是列出 Node 在技术上的许多定义,如:


  • Node.js 是一个基于 Chrome V8 JavaScript 引擎构建的 Javascript 运行时环境。

  • Node.js 使用事件驱动的非阻塞 I/O 模型,这使其轻量且高效。

  • Node 包生态系统(npm)是全世界最大的开源库生态系统。


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


这才是为什么它能成为每个 Web 开发人员必备之物的真正原因。


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


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


因此,为了挖掘 Node 的世界,我们将检查其核心的部分:事件循环,事实上,事件循环就是负责 Node 非阻塞 I/O 模型的部分。

对线程认识的简要刷新

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


每当我们运行一个程序时,我们都会创建一个它的实例,并且我们会调用一些内部线程,他们是与该实例相关联的。线程可以看作是 CPU 必须执行的操作单元。许多不同的线程可以与程序的单个进程相关联。以下是一个图形,它可以帮助你在脑海中形成这个概念:



线程的简单图形


在谈论线程时,最重要的一点是:机器如何确定在某个时刻处理哪个线程?


众所周知,我们的机器资源(CPU、RAM)是有限的,因此正确确定我们将资源分配在哪里非常重要,或者说,哪些操作应该优先于其他操作。这一切都必须实现,而且同时,需要确保没有任何操作耗费太多时间,因为没有人喜欢笔记本电脑速度过慢。


用于解决资源分配问题的机制就叫作调度,它由我们的操作系统中称为 OS 调度程序的实体来管理。这背后的逻辑可能非常复杂,但总而言之,我们可以将执行此操作的两大方法组合在一起:




多核机器如何处理线程


  • 使用优化逻辑,以减少死锁时间:这是对我们来说最切实的方法。如果我们仔细研究一下线程是如何工作的,我们就会看到 OS 调度程序可以识别出 CPU 何时在等待其他资源来执行某个作业,以便分配这个资源来同时执行其他操作。这通常发生在非常昂贵的 I/O 操作上,例如硬盘读取。

事件循环

现在我们已经对线程的工作原理有了新的了解,我们终于可以解决 Node.js 事件循环逻辑了。通过阅读本文,你会了解前面的解释它背后的原因,而且每个部分都会自行找到正确的位置。


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


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

详情

现在让我们尝试模拟事件循环的工作原理以及它如何使我们的程序开始工作。为此,我将假装自己正在使用一个名为 myProgram 的文件为 Node 提供信息,然后我们再详细了解事件循环将执行的所有操作。



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



事件循环的图形说明

第 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 线程池的特殊线程池。


此线程池由四个线程组成,它们负责委派对事件循环来说太繁重的操作。上述事件循环逻辑中的长时间运行的任务代表此处所描述的对于事件循环而言过于昂贵的操作。

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

从这个意义上说,虽然在上述过程中涉及到了一些类似堆栈的结构,但更准确的答案是事件循环由一系列阶段组成,每个阶段都有自己的特定任务,而且所有阶段都以循环重复的方式被处理。有关事件循环确切结构的更多信息,请看这个对话

结论

了解事件循环是使用 Node.js 的重要部分,无论你是想获得有关此技术的更多见解、了解如何提高其性能,还是希望找到学习一个新工具的新的且有趣的理由。


本指南应当能帮助你探索这个主题。请在下面发表评论,你的意见和反馈将有助于每个人更好地学习。


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


2019-08-06 10:062703
用户头像

发布了 34 篇内容, 共 20.1 次阅读, 收获喜欢 47 次。

关注

评论

发布
暂无评论
发现更多内容

带你读论文丨S&P21 Survivalism: Living-Off-The-Land 经典离地攻击

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 8 月 PK 榜

开放网关架构演进

阿里技术

网关 开放网关

生成式AI技术:引领未来内容创作

百度开发者中心

物联网, 云计算, 文心一言 人工智能、

解决跨时区跨语言的国外大文件传输问题

镭速

跨国传输大文件 传输大文件 国外大文件传输

RocketMQ 5.0 架构解析:如何基于云原生架构支撑多元化场景

阿里巴巴云原生

阿里云 RocketMQ 云原生

软件测试/测试开发丨Python 错误与异常 学习笔记

测试人

Python 程序员 软件测试 自动化测试 测试开发

​Kubernetes的演变:从etcd到分布式SQL的过渡

互联网工科生

Kubernetes etcd 部署

报名开启 | HarmonyOS第一课“营”在暑期系列直播

HarmonyOS开发者

HarmonyOS

MySQL的Json类型字段IN查询分组和优化方法

北桥苏

MySQL SQL优化 虚拟字段

低代码系列——初步认识低代码

互联网工科生

软件开发 低代码 JNPF

让企业内部开发游刃有余,平台工程到底是什么?

树上有只程序猿

DevOps 软件开发 平台工程

介绍一下我们的开源“充电之旅” - 两位新晋 Apache Flink Committer 专访

字节跳动云原生计算

flink 开源 字节跳动 流式计算

画质提升+带宽优化,小红书音视频团队端云结合超分落地实践

小红书技术REDtech

音视频 小红书

备份或同步数据?跨国大文件传输的不同需求与解决方案

镭速

大文件传输 跨国文件传输

拯救开源:《网络韧性法案》即将带来的悲剧

开源雨林

开源 LICENSE

技术分享| WebRTC之SDP详解

anyRTC开发者

WebRTC RTC sdp

SRE方法论之服务质量目标

不思jo

SRE

关于云原生开源开发者沙龙「微服务X消息队列专场」的延期通知

阿里巴巴云原生

阿里云 微服务 云原生 消息队列

中路对线发现正在攻防演练中投毒的红队大佬

墨菲安全

网络安全 npm 投毒 投毒分析

校源行丨开放原子开源基金会赴苏州大学走访交流

开放原子开源基金会

开源

揭秘!CIPU最新秘密武器–弹性RDMA的技术解析与实践

阿里云弹性计算

开发者不需要成为 K8s 专家!!!

北京好雨科技有限公司

Kubernetes 开发者 PaaS #云原生

手把手带你玩转HetuEngine:资源规划与数据源对接

华为云开发者联盟

大数据 后端 华为云 华为云开发者联盟 企业号 8 月 PK 榜

生成式AI:人工智能新范式,引领生产力革命

百度开发者中心

#人工智能 文心一言

九科信息成功签约中交财资管理(香港)有限公司-境外银行账户可视化管控流程自动化系统项目

九科Ninetech

和鲸 ModelWhale 与中科可控多款服务器完成适配认证,赋能中国云生态

ModelWhale

云原生 服务器 信创

小米交卷大模型,全新小爱同学实测来了

Openlab_cosmoplat

小米 大模型 小爱同学

科技前沿的助力:探索语音标注平台的奇迹

数据堂

深入解析Node.js事件循环工作机制_语言 & 开发_Piero Borrelli_InfoQ精选文章