Node.js Event Loop各阶段讲解

Event Loop阶段描述图

timers

timer阶段处理setTimeout于setInterval回调,开始处理的时机与poll阶段有关联。

pending callbacks

该阶段执行某些系统操作的回调,比如TCP套接字在连接时收到ECONNREFUSED。

网上有一些将该阶段称为I/O callbacks的文章都是过时错误的,具体可以移步Node.js官方库下面的这个issue: #1118

idle, prepare

内部使用,忽略。

poll

poll是一个核心阶段,等新I/O事件的触发,以及执行I/O相关回调。Node.js中出现异步的绝大部分情况都是I/O操作,它们的回调基本都在这个阶段被执行。

poll阶段主要做两件事:

  • 计算需要为新的的I/O事件等待多久

当进入poll阶段,如果队列为空且不存在setImmediate与就绪的timer,Node.js会在这里block一定的时间等待新的I/O事件到来,然后立即执行其回调。这种情况具体block等待多久是不具体的,但如果在block一定时间后仍没有新到达的I/O事件,可以肯定循环依旧会进入check阶段或者回到timer阶段。

  • 处理该阶段队列中的事件

当进入poll阶段,如果队列不为空且没有就绪的timer,Node.js会在这里执行队列中的callback直到队列为空或者执行的callback数达到系统设定的某个值。随后Node.js检查是否存在预设的setImmediate,存在话就进入check阶段,否则开始检查timer就绪情况选择回到timer阶段或者进入check阶段。

对于poll阶段,通过阅读官方的文档有些细节也没弄清楚,用伪代码表示出来:

enter pool phase:
if (has timer scheduled) {
  // 官方没有提到这种情况会做什么
}
else {
  if (isEmpty(queue)) {
    if (has(setImmediate)) {
      // 进入check阶段
    }
    else if (!isEmpty(timer)) {
      // 回到timer阶段
    }
    else {
      // 等待新的I/O事件
      // 新的I/O事件触发回调立即执行,执行完成之后的逻辑不清楚
    }
    // 目前看来只有存在setImmediate时才会进入check阶段,这肯定不合理
  }
  if (!isEmpty(queue)) {
    let result = execute(queue);
    if (result === 'queue is empty') {
      // 官方没讲后续逻辑
      // 猜测是回到队列为空的处理逻辑中
    }
    if (result === 'reached hard limit') {
      // 官方没有解释这里的后续逻辑
      // 也许与queue is empty一样对待
    }
  }
}

疑惑重点是从poll阶段出来的时机以及去向不是非常明确,但以我目前的水平和精力只能到此为止。

check

当poll阶段执行完成会进入到check阶段执行,该阶段的执行内容是所有setImmediate回调。

close callbacks

socket的异常关闭,'close'事件的回调会在该阶段执行。

process.nextTick

process.nextTick经常被用来做异步调用,但它并不属于事件循环的内容,process.nextTick中的回调被放在nextTickQueue中等待“当前操作”完成后被立即处理,与事件循环中的阶段没有联系,当前操作的原文定义是:“An operation is defined as a transition from the underlying C/C++ handler, and handling the JavaScript that needs to be executed.”,指的是在一段Javascript代码执行完切换到C/C++层时会处理nextTickQueue。

文章提到了一个特例是Deduplication,这是Node.js内部一个优化特性,当在timer和check阶段,同时有多个需要执行的回调时,切换只会发生一次,所以nextTick回调执行在这种情况下看似有所延后。

代码示例:

setImmediate(() => {
  console.log('1');
  process.nextTick(() => console.log('2'));
});
setImmediate(() => {
  console.log('3');
  process.nextTick(() => console.log('4'));
});

存在两个setImmediate,进入check阶段后需要在执行所有setImmediate的回调代码后才会产生切换,从而执行nextTick回调,因此上面代码的运行结果是:“1 3 2 4”,除上述场景外,nextTick都会先于setImmediate执行。

总结

因为Node.js的Event Loop我看了有那么2、3回,但经常忘,所以这次记录下来,做个备忘。由于太多知识容易忘记,又发现写文章的一个优点:“帮助记忆便于复习”。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Node.js之readline模块的使用详解

    什么是readline readline允许从可读流中以逐行的方式读取数据,比如process.stdin等. 在node.js命令行模式下默认引入了readline模块,但如果是使用node.js运行脚本的话,则需要自己通过require('readline')方式手动引入该模块. 怎么使用readline 创建实例 首先.创建一个接口实例,提供一个Object类型的参数.参数如下: input: 监听的可读流(必需) output: 写入readline的可写流(必需) completer:

  • 详解基于React.js和Node.js的SSR实现方案

    基础概念 SSR:即服务端渲染(Server Side Render) 传统的服务端渲染可以使用Java,php 等开发语言来实现,随着 Node.js 和相关前端领域技术的不断进步,前端同学也可以基于此完成独立的服务端渲染. 过程:浏览器发送请求 -> 服务器运行 react代码生成页面 -> 服务器返回页面 -> 浏览器下载HTML文档 -> 页面准备就绪 即:当前页面的内容是服务器生成好给到浏览器的. 对应CSR:即客户端渲染(Client Side Render) 过程:浏

  • Node.js Stream ondata触发时机与顺序的探索

    上次写Stream pipe细节时,在源码中发现一段无用逻辑,由此引发了对Stream data事件触发时机与顺序的探索. 无用逻辑 当时研究pipe细节是基于Node.js v8.11.1的源码,其中针对上游的ondata事件处理有如下一段代码: // If the user pushes more data while we're writing to dest then we'll end up // in ondata again. However, we only want to in

  • Node.js + express实现上传大文件的方法分析【图片、文本文件】

    本文实例讲述了Node.js + express实现上传大文件的方法.分享给大家供大家参考,具体如下: 对于大文件的上传我们首先要引入一个叫做 multer 的库: npm install --save multer 关于这个库,大家可以查阅官方文档: 点击跳转 https://www.npmjs.com/package/multer 我们先将库引入我们的项目中: var multer = require('multer') var upload = multer({ dest: 'upload

  • Node.js动手撸一个静态资源服务器的方法

    简介 本文介绍了一个简单的静态资源服务器的实例项目,希望能给Node.js初学者带来帮助.项目涉及到http.fs.url.path.zlib.process.child_process等模块,涵盖大量常用api:还包括了基于http协议的缓存策略选取.gzip压缩优化等:最终我们会发布到npm上,做成一个可以全局安装.使用的小工具.麻雀虽小,五脏俱全,一想是不是还有点小激动?话不多说,放码过来. 文中源码地址在最后附录中. 可先行体验项目效果: 安装:npm i -g here11 任意文件夹

  • 使用Node.js实现一个多人游戏服务器引擎

    摘要 听说过文字冒险游戏吗? 如果你的年龄足够大的话(就像我一样),那么你可能听说过.甚至玩过"back in the day".在本文中,我将向你展示编写的整个过程.这不仅仅是一个文本冒险游戏,而是一个能让你和你的朋友们一起玩的,可以进行任何剧情的文本冒险游戏引擎. 没错,我们将通过在添加多人游戏功能来增加它的趣味性. 文字冒险是最早的 RPG 形式的游戏之一,回到还没有图形画面的时代,你只能通过阅读 CRT 显示器上黑色背景下的描述,并且依赖自己的想象力来推动游戏剧情的发展. 如果

  • Node.js + express基本用法教程

    本文实例讲述了Node.js + express基本用法.分享给大家供大家参考,具体如下: 这里来讲下 express 框架的使用,编译的环境是 VS Code ,这里我已经配饰了阿里的镜像,所有 npm 指令用 cnpm 代替 首先学会向 Node.js 种引入 express 非常建党只需两步,输入指令: cnpm init 然后就可以载入 express cnpm install express -save 到此为止 express 救成功导入了 这里介绍一个技巧: 输入: cnpm in

  • 零基础之Node.js搭建API服务器的详解

    零基础之Node.js搭建API服务器 这篇文章写给那些Node.js零基础,但希望自己动手实现服务器API的前端开发者,尝试帮大家打开一扇门. HTTP服务器实现原理 HTTP服务器之所以能提供前端使用的API,其实现原理是服务器保持监听计算机的某个端口(通常是80),等待客户端请求,当请求到达并经过一系列处理后,服务器发送响应数据给到前端. 平时大家通过Ajax调用API,即是发起一次请求,经过服务器处理后,得到结果,然后再进行前端处理.如今使用高级编程语言,要实现服务器那部分功能已经变得非

  • node.js实现微信开发之获取用户授权

    本篇主要讲述,如何在微信中打开自家页面后,弹窗请求用户授权,以便拿到用户的微信信息. 首先说一下,完成自定义分享信息的,从无到有的流程: 基础硬件服务: 需要一个公网可以访问的有效域名: 购买域名,并备案,我是在阿里云购买的,备案需要十几个工作日. 购买ip,然后设置上面的域名,解析到该ip,这个时间可以快到忽略. 拥有自己的服务器,来存放自己页面项目: 我还是在阿里云购买购买服务器,这个花费最大,几百元一年的使用权. 而且这个服务器,本质就是一台电脑,是电脑就有配置,我目前只是自己学习使用,配

  • Node.js使用supervisor进行开发中调试的方法

    如果你有 PHP 开发经验,会习惯在修改 PHP 脚本直接刷新浏览器以查看结果,而你 在开发 Node.js 实现的 HTTP 应用时会发现,无论你修改了代码的哪一个部分,都必须终止Node.js然后重新运行. 这是因为 Node.js 只有在第一次引用到某一部分时才会去解析 本文件,以后都会直接访问内存,避免重复载入,而 PHP 则是重新读取并解析脚本(如果没有专门的优化配置). 在开发Node.js实现HTTP应用时会发现,无论你修改了代码的哪一部分,都必须终止Node.js再重新运行才会奏

随机推荐