NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

深入解析 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:062360
用户头像

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

关注

评论

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

面试官让我讲讲MySQL三大核心日志实现原理

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟

Flink 在蚂蚁实时特征平台的深度应用

Apache Flink

大数据 实时计算 flink 实战

可扩展性是什么意思?为什么企业采购软件时候需要考虑可扩展性?

行云管家

软件 可扩展性 采购

数字人直播带货的前景如何?

青否数字人

直播回顾 | 去哪儿网研发数字化洞察实践

思码逸研发效能

智能测试时代来临!人工智能如何颠覆测试开发传统模式?

测试人

人工智能 软件测试 自动化测试 测试开发

hal库中串口常用函数介绍

百度搜索:蓝易云

云计算 Linux 运维 云服务器 HAL

Qualcomm’s “core”QCN9274 leads WiFi 7 to break through the boundaries of wireless connections

wallysSK

我是怎么用静态IP代理为Google账号保驾护航的

陈橘又青

零门槛AI开发平台EasyDL:百亿参数大模型ERNIE的加持

百度开发者中心

人工智能 深度学习 AI

Chatbot具体需要如何搭建

百度搜索:蓝易云

云计算 Linux 运维 chatbot 云服务器

你所在的行业,有必要做小程序么?

天津汇柏科技有限公司

小程序 小程序开发 开发小程序

思码逸荣获 TID 质量竞争力大会“2023 软件研发优秀工具奖”

思码逸研发效能

大模型时代下的文档识别与分析

百度开发者中心

人工智能 文档 大模型

通俗易懂剖析Go Channel:理解并发通信的核心机制

王中阳Go

Go golang 面经 Go 语言 Go学习路线

C#中使用IntPtr.Size属性来判断当前系统是32位还是64位

百度搜索:蓝易云

C# 云计算 Linux 运维 云服务器

AWS安全组是什么?有什么用?

行云管家

云计算 AWS 安全组 亚马逊云

数字人主播要抢真人饭碗?

青否数字人

实例详解在Go中构建流数据pipeline

华为云开发者联盟

开发 华为云 华为云开发者联盟 Go并发范式

NGINX Agent 的可观测性和远程配置

NGINX开源社区

orca市值机器人/刷量机器人/做市机器人

区块链技术

智能测试时代来临!人工智能如何颠覆测试开发传统模式?

霍格沃兹测试开发学社

细粒度的代码权限怎么做?极狐GitLab 代码所有者来帮忙

极狐GitLab

交互式数字人终端互动大屏支持多种场景交互!

青否数字人

数字人

教你如何拿Merlin Chain空投,附视频教程

石头财经

教你如何拿Merlin Chain空投,附视频教程

BlockChain先知

活动回顾 | 金融科技提质增效的成功方法论与实践案例

思码逸研发效能

一文搞懂设计模式—模板方法模式

Java随想录

Java 设计模式

AI数字虚拟人来了你会失业吗?

小齐写代码

AI大模型时代:企业如何构建数据智能基础设施

百度开发者中心

AI 大模型 人工智能’

SpEL应用实战

得物技术

Java sping

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