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

更新日期: 2019-07-07阅读: 1.8k标签: 机制

本文从对线程、事件循环、事件循环常见的问题和错误上分别进行说明,进一步探索了 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/


链接: https://www.fly63.com/article/detial/4562

浅析前端页面渲染机制

作为一个前端开发,最常见的运行环境应该是浏览器吧,为了更好的通过浏览器把优秀的产品带给用户,也为了更好的发展自己的前端职业之路,有必要了解从我们在浏览器地址栏输入网址到看到页面这期间浏览器是如何进行工作的

这一次,彻底弄懂 JavaScript 执行机制

javascript是一门单线程语言,Event Loop是javascript的执行机制.牢牢把握两个基本点,以认真学习javascript为中心,早日实现成为前端高手的伟大梦想!

创建js hook钩子_js中的钩子机制与实现

钩子机制也叫hook机制,或者你可以把它理解成一种匹配机制,就是我们在代码中设置一些钩子,然后程序执行时自动去匹配这些钩子;这样做的好处就是提高了程序的执行效率,减少了if else 的使用同事优化代码结构

小程序的更新机制_如何实现强制更新?

在讲小程序的更新机制之前,我们需要先了解小程序的2种启动模式,分别为:冷启动和热启动。小程序不同的启动方式,对应的更新情况不不一样的。无论冷启动,还是热启动。小程序都不会马上更新的,如果我们需要强制更新,需要如何实现呢?

基于JWT的Token认证机制实现及安全问题

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。其JWT的组成:一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。

web前端-JavaScript的运行机制

本文介绍JavaScript运行机制,JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。

轮询机制解决后端任务回调问题

现在有一个需求,前端有一个按钮,点击以后会调用后端一个接口,这个接口会根据用户的筛选条件去hadoop上跑任务,将图片的base64转为img然后打包成zip,生成一个下载连接返回给前端,弹出下载框。hadoop上的这个任务耗时比较久

JavaScript预解释是一种毫无节操的机制

js代码执行之前,浏览器首先会默认的把所有带var和function的进行提前的声明或者定义:1.理解声明和定义、2.对于带var和function关键字的在预解释的时候操作不一样的、3.预解释只发生在当前的作用域下

js对代码解析机制

脚本执行js引擎都做了什么呢?1.语法分析 2.预编译 3.解释执行。在执行代码前,还有两个步骤;语法分析很简单,就是引擎检查你的代码有没有什么低级的语法错误 ,查找全局变量声明(包括隐式全局变量声明,省略var声明),变量名作全局对象的属性,值为undefined

web认证机制

以前对认证这方面的认识一直不太深刻,不清楚为什么需要token这种认证,为什么不简单使用session存储用户登录信息等。最近读了几篇大牛的博客才对认证机制方面有了进一步了解。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!