首页 > 编程语言 >Nodejs事件循环小记

Nodejs事件循环小记

时间:2024-08-09 15:39:22浏览次数:7  
标签:回调 console log setTimeout Nodejs setImmediate 循环 执行 小记

执行原理

  • 当 Node.js 启动时,会先初始化 Event Loop,然后执行提供的输入脚本(主模块同步代码),过程中可能会产生异步 API 调用、定时器或调用 process.nextTick(),然后开始处理事件循环。

  • Node.js 的 Event Loop 分为 6 个阶段,会按照顺序反复执行,每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。

  • 每执行完一个阶段的回调队列,就会去执行 process.nextTick 和 Promise 2个微任务队列,然后进入下一个阶段,这就是 Node.js Event Loop 的过程。

  • 其中,process.nextTick 优先级高于 Promise,但是如果当前执行的是 Promise,那么如果执行过程中产生了 process.nextTick 和 Promise,那么后续的 Promise 会先于 process.nextTick 执行,直到 Promise 微任务队列清空。

阶段概述

  • 定时器:此阶段执行由 setTimeout() 和 setInterval() 安排的回调。

  • 待处理回调:执行被推迟到下一次循环迭代的 I/O 回调。

  • 空闲,准备:仅在内部使用。

  • 轮询:检索新的 I/O 事件,执行 I/O 相关回调(几乎是除了关闭回调、由定时器回调和 setImmediate 回调的所有回调)。

  • 检查:setImmediate() 回调在此处调用。

  • 关闭回调:一些关闭回调,例如 socket.on('close', ...)。

需要关注的主要是定时器、轮询、检查和关闭回调

当没有任何 I/O 任务时,事件循环会在轮询阶段等待,进入休眠期,值到新的 I/O 任务插入为止。

相关 API

// 检查阶段执行的异步函数
setImmediate()

// 当前 Event Loop 阶段执行完毕后,下个 Event Loop 阶段执行之前执行的异步函数
// 从技术实现上来说,它不是事件循环的一部分
process.nextTick()

// V8 引擎语言层面实现的一种微任务函数,也不是事件循环的一部分
Promise

setImmediate() 与 setTimeout()

两者的执行顺序,根据调用它们的上下文而有所不同。

情况1:不存在全局同步代码,直接在主模块执行时

// test.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

// 执行顺序不固定
// 原因:受到进程性能的约束(这可能会受到机器上运行的其他应用的影响)

情况2:存在全局同步代码,直接在主模块执行时

// test.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

console.log('start');

// start -> timeout -> immediate
// 原因:先执行同步代码(2个异步函数已被加入各自队列),再开始 Event Loop,定时器阶段先于检查阶段,因此结果如上

情况3:.mjs代码,不存在全局同步代码,直接在主模块执行时

// test.mjs
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

// immediate -> timeout
// .mjs 本质上是一个 async 函数,因此实际代码等于:

async function main() {}
main().then(() => {
  setTimeout(() => {
    console.log('timeout');
  }, 0);

  setImmediate(() => {
    console.log('immediate');
  });
})

// 原因:
// 1. 先执行同步代码 main(),再开始 Event Loop。
// 2. 第一轮循环中,定时器阶段检查,未发现队列中有回调函数,然后执行微任务 then 回调。
// 3. 微任务回调执行过程中,将 setTimeout 和 setImmediate 加入各自队列。
// 4. 然后,第一轮循环继续进行,终于达到了检查阶段,发现了检查队列中存在 setImmediate,执行。
// 5. 最后,第一轮循环执行完毕,开始第二轮循环,定时器阶段检查,发现了上轮加入的 setTimeout,执行

情况4:.mjs代码,存在全局同步代码,直接在主模块执行时

// test.mjs
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

console.log('start');

// start -> immediate-> timeout
// .mjs 本质上是一个 async 函数,因此实际代码等于:

async function main() {
  console.log('start');
}
main().then(() => {
  setTimeout(() => {
    console.log('timeout');
  }, 0);

  setImmediate(() => {
    console.log('immediate');
  });
})

情况5:执行 I/O 任务,在 I/O 回调中加入

// test.js 或 test.mjs
// 带全局代码 或 不带全局代码
const fs = require('node:fs');
fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout');
  }, 0);
  setImmediate(() => {
    console.log('immediate');
  });
});

// immediate -> timeout
// 原因:因为 I/O 回调时,肯定处于轮询阶段,那么下一个阶段一定是检查阶段,所以,一定是 setImmediate 先执行。

标签:回调,console,log,setTimeout,Nodejs,setImmediate,循环,执行,小记
From: https://www.cnblogs.com/kanyu/p/18350591

相关文章

  • 【前端】NodeJS:HTTP协议
    文章目录HTTP协议1概念2请求报文的组成3HTTP的请求行4请求头5HTTP的请求体6响应报文的组成7创建HTTP服务7.1操作步骤7.2测试7.3注意事项8浏览器查看HTTP报文8.1查看请求行和请求头8.2查看请求体8.3查看URL查询字符串8.4查看响应行与响应头8.5查看响应体......
  • 【前端】NodeJS:NodeJS模块化
    文章目录1NodeJS模块化1.1模块化与模块1.2模块化项目1.3模块化好处2模块暴露数据2.1模块初体验2.2暴露数据3导入(引入)模块4导入模块的基本流程5CommonJS规范1NodeJS模块化1.1模块化与模块将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称......
  • 双碳目标下基于“遥感+”集成技术的碳储量、碳排放、碳循环、温室气体等多领域监测与
    以全球变暖为主要特征的气候变化已成为全球性环境问题,对全球可持续发展带来严峻挑战。2015年多国在《巴黎协定》上明确提出缔约方应尽快实现碳达峰和碳中和目标。2019年第49届IPCC全会明确增加了基于卫星遥感的排放清单校验方法。随着碳中和目标以及全球碳盘点的现实压力,基于......
  • JAVA修饰符、运算符、循环语句
    JAVA修饰符修饰符用来定义类、方法或者变量,通常放在语句的最前端一、访问修饰符1、default默认访问修饰符:在同一包内可见,不使用任何修饰符,使用对象为类、接口、变量、方法,访问级别是包级别(package-level),即只能被同一包中的其他类访问2、private私有访问修饰符:最严格的访问级......
  • nodejs语言,MySQL数据库;springboot的个性化资讯推荐系统66257(免费领源码)计算机毕业设计
    摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,个性化资讯推荐系统当然也不能排除在外。个性化资讯推荐系统是以实际运用为开发背景,运用软件工程原理和开发方法,采用springboot技术构建的一个管理系统。整......
  • 关于嵌套循环之深入理解
    关于嵌套循环之深入理解#外层循环遍历第一维(深度)fordepthinrange(len(cube)):#中层循环遍历第二维(行)forrowinrange(len(cube[depth])):#内层循环遍历第三维(列)forcolinrange(len(cube[depth][row])):print(cube......
  • 循环神经网络和自然语言处理二-文本情感分类
    一.案例介绍为了练习一下wordembedding,现在有一个经典的数据集IMDB数据集,其中包含了5完条流行电影的评价,训练集25000条,测试集25000条,根据这些数据,通过pytorch完成模型,实现对评论情感进行预测二.思路首先可以把上述问题定义为分类问题,情感评分分为1-10分。十个类别,那么怎样......
  • 循环神经网络和自然语言处理一
    目录一.分词1.分词工具2.分词的方法3.N-gram表示方法二.向量化1.one-hot编码2.wordembedding3.wordembeddingAPI4.数据形状改变既然是自然语言,那么就有字,词,句了一.分词1.分词工具tokenization,jieba,清华大学的分词工具THULAC等等2.分词的方法对于中文我们可......
  • gcc使用小记
    gcc使用小记1.gcc使用gcc-ofilenamefilename.c释义:-o:表示的是文件输出名称(由自己自定义)filename.c:表示的是源文件的名称2.在源文件中导入头文件<math.h>后gcc的编译命令gcc-ofilenamefilename.c-lm释义:编译时需要注意,在Linux系统下,C源文件若调用了math......
  • dp 套 dp(dp of dp)小记
    其实并不是什么很高大上的东西,就是把内层dp的结果压到外层dp的状态里。通常解决的是“限制某种值为\(x\)的方案数”之类的问题,而限制的值通常是一个经典的dp问题。没有啥好直接介绍的,就写三道做过的题。BZOJ3864Heromeetdevil题目链接算是一道入门题目。我们先回......