【Node.js】事件循环

Node.js 中的事件循环是基于单线程的异步非阻塞模型。它是 Node.js 的核心机制,用于处理非阻塞的 I/O 操作和异步事件。
在这里插入图片描述

1. Node.js 事件循环介绍

Node.js 的事件循环是一个 Event Loop,通过异步回调函数的方式实现非阻塞的处理。事件循环会在主线程上不断地执行,监听和处理事件,执行相应的回调函数。

Node.JS的事件循环比浏览器端复杂很多。Node.js的运行机制如下:

  • V8引擎解析JavaScript脚本。
  • 解析后的代码,调用Node API 。
  • libuv 库(C++)负责Node API的执行。它将不同的任务分配给不同的线程,形成一个事件循环,以异步的方式将任务的执行结果返回给V8引擎。
  • V8引擎再将结果返回给用户。
    在这里插入图片描述

2. 事件循环的六个阶段

libuv 引擎中的事件循环分为六个阶段,每个阶段都有对应的回调队列(回调函数的集合)和触发器,依次执行以下步骤:

  • timers 阶段:处理定时器和 setTimeout/setInterval 设置的回调函数。
  • I/O callbacks 阶段:处理上一轮循环中少量未执行的与 I/O 相关的回调函数,例如网络请求的响应、文件读写等。
  • idle, prepare 阶段:内部使用。
  • poll 阶段:检索新的 I/O 事件,执行与 I/O 相关的回调函数。
  • check 阶段:执行 setImmediate 设置的回调函数。
  • close callbacks 阶段:执行一些关闭的回调函数,例如 socket.on('close', ...)
    在这里插入图片描述

外部输入数据一>轮询阶段(poll)->检查阶段(check)->关闭事件回调阶段(close callback)->定时器
检测阶段(timer)->I/O事件回调阶段(I/O callbacks)->闲置阶段(idle、prepare)->轮询阶段(按照该顺序反复运行)

timers

timers阶段会执行setTimeout和setInterval回调,并且是由poll阶段控制的。同样,在Node.js中定时器指定的时间也不是准确时间,只能是尽快执行。

poll

poll 是一个至关重要的阶段,这一阶段中,系统会做两件事情:

  • 回到timer阶段执行回调
  • 执行 I / O 回调
    并且在进入该阶段时如果没有设定了timer的话,会发生以下两件事情:
  • 如果 poll 队列不为空,会遍历 poll 回调队列并同步执行,直到队列为空或者达到系统限制
  • 如果 poll 队列为空时,会有两件事发生:
    • 如果有setlmmediate回调需要执行,poll 阶段会停止并且进入到check阶段执行回调
    • 如果没有setlmmediate回调需要执行,会等待其他异步任务回调被加入到队列中并立即执行回调,这里同样会有个超时时间,防止一直等待下去

当然设定了timer的话且 poll 队列为空,则会判断是否有timer超时,如果有的话会回到timer阶段执行回调。

假设 poll 被堵塞,那么即使 timer 已经到时间了也只能等着,这也是为什么上面说定时器指定的时间并不是准确的时间。

const fs = require('fs')
const start = Date.now()
setTimeout(()=>{console.log('setTimeout', Date.now() - start)  // 503ms
}, 200)
fs.readFile('./index.js', ()=>{const start = Date.now()console.log('文件读取结束')// 强行拖时间while(Date.now() - start < 500) {}
})
//timer队列 setTimeout 异步需要等待 poll 全部执行完之后再执行
//poll队列 readFile

check

setimmediate()的回调被加入check队列中,从事件循环的阶段图可以知道,check阶段的执行顺序在poll 阶段之后。

3. 一些注意点:

  • setTimeout 和 setImmediate 区别:setImmediate 在 poll阶段完成时执行,即check阶段;setTimeout 在 poll 阶段为空闲时,且设定时间到达后执行,但在 timer 阶段执行
setTimeout(function() {console.log('timeout');
}, 0)
setImmediate(function() {console.log('immediate');
})

他们执行的先后顺序是未知的,进入事件循环的准备也是需要花费成本的,如果准备阶段花费了大于 1ms 的时间,那么在 timer 阶段就会直接执行 setTimeout 回调;否则就先执行 setImmediate 回调。

但当二者在异步 I/O callback内部调用时,总是先执行setlmmediate, 再执行setTimeout。例如:

const fs = require('fs')
fs.readFile(__filename,()=>setTimeout(()=>{console.log('timeout');}0)setImmediate(()=>{console.log('immediate')})
})
// immediate
// timeout

在上述代码中,setlmmediate永远先执行。因为两个代码写在I/O回调中,I / O 回调是在 poll 阶段执行,当回调执行完毕后队列为空,发现存在setlmmediate回调,所以就直接跳转到check阶段去执行回调了。

  • process.nextTick
setTimeout(() => {console.log('timer1')Promise.resolve().then(function () {console.log('promise1')})
}, 0)
process.nextTick(() => {console.log('nextTick')process.nextTick(() => {console.log('nextTick')process.nextTick(() => {console.log('nextTick')process.nextTick(() => {console.log('nextTick')})})})
})
// timers: setTimeout
// 微任务队列:nextTick

nextTick 有一个自己的队列,独立于事件循环,每个阶段执行完成后,如果存在 nextTick,就会清空队列中的所有回调函数,并且优先于其他 微任务队列 执行。

4. Node.js 事件循环和浏览器事件循环的区别:

  • 浏览器环境下,微任务队列在每一个宏任务执行完之后执行。
  • node.js 环境,微任务会在事件循环的各个阶段之间执行,每一个阶段执行完毕,都会去清空微任务队列中的任务。

通过事件循环,Node.js 实现了高效的异步 I/O 操作,并能够处理大量的并发连接,适用于构建高性能的网络应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/700953.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

港股大反攻结束了吗?

‘港股长线见顶了吗&#xff1f;今天开盘就是最高点&#xff0c;然后一路跳水&#xff0c;市场又是一片恐慌。到底是健康的技术性回调&#xff0c;还是市场已经见顶&#xff1f; 港股此轮“大反攻”中&#xff0c;科网股表现十分亮眼。今日港股盘后&#xff0c;阿里巴巴、腾讯…

【Shell】Shell编程之函数

目录 1.Shell函数定义 2.Shell函数的作用 3.函数返回值 4.函数传参 5.函数变量的作用范围 案例 1.Shell函数定义 格式1 function 函数名 { 命令序列 } 格式2 函数名() { 命令序列 } 2.Shell函数的作用 使用函数可以避免代码重复 使用函数可以将大的工程分割为若…

DeepSort / Sort 区别

推荐两篇博文,详细介绍了deepsort的流程及代码大致讲解: https://blog.csdn.net/qq_48764574/article/details/138816891 https://zhuanlan.zhihu.com/p/196622890 DeepSort与Sort区别: 1、Sort 算法利用卡尔曼滤波算法预测检测框在下一帧的状态,将该状态与下一帧的检测结…

什么是工具? 从语言模型视角的综述

24年3月CMU和上海交大的论文“What Are Tools Anyway? A Survey from the Language Model Perspective”。 到底什么是工具&#xff1f; 接下来&#xff0c;工具在哪里以及如何帮助语言模型&#xff1f; 在综述中&#xff0c;对语言模型使用的外部程序工具进行了统一定义&…

【RAG 论文】UPR:使用 LLM 来做检索后的 re-rank

论文&#xff1a;Improving Passage Retrieval with Zero-Shot Question Generation ⭐⭐⭐⭐ EMNLP 2022, arXiv:2204.07496 Code: github.com/DevSinghSachan/unsupervised-passage-reranking 论文&#xff1a;Open-source Large Language Models are Strong Zero-shot Query…

智慧公厕系统:改变“上厕所”体验的科技革新

公共厕所是城市建设中不可或缺的基础设施&#xff0c;然而&#xff0c;由于较为落后的管理模式&#xff0c;会常常存在着管理不到位、脏乱差的问题。为了改善公厕的使用体验&#xff0c;智慧公厕系统应运而生&#xff0c;并逐渐成为智慧城市建设的重要组成部分。本文将以智慧公…

“打工搬砖记”中首页的功能实现(一)

文章目录 打工搬砖记秒薪的计算文字弹出动画根据时间数字变化小结 打工搬砖记 先来一个小程序首页预览图&#xff0c;首页较为复杂的也就是“秒薪”以及弹出文字的动画。 已上线小程序“打工人搬砖记”&#xff0c;进行预览观看。 秒薪的计算 秒薪计算公式&#xff1a;秒薪 …

特产销售|基于Springboot+vue的藏区特产销售平台(源码+数据库+文档)​

目录 基于Springbootvue的藏区特产销售平台 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道…

Golang SDK安装

windows环境安装 1.链接: 下载地址 2.安装SDK 检查环境变量&#xff1a; 3.开启go modules,命令行执行一下命令&#xff1a; go env -w GO111MODULEon4.设置国内代理&#xff0c;命令行执行一下命令&#xff1a; go env -w GOPROXYhttps://proxy.golang.com.cn,https:/…

如何使用恢复模式修复Mac启动问题?这里提供详细步骤

如果你的Mac无法启动,不要惊慌,Mac有一个隐藏的恢复模式,你可以使用它来诊断和修复任何问题,或者在需要时完全重新安装macOS。以下是如何使用它。 如何在Mac上启动到恢复模式 你需要做的第一件事是启动到恢复模式。尽管操作说明会因你使用的Mac电脑而异,但幸运的是,启动…

14.正交向量与子空间

文章目录 1. 四个子空间的相互关系2. 正交向量3. 无解方程求解 1. 四个子空间的相互关系 对于m行n列的矩阵A来说&#xff0c;矩阵A的行空间的秩等于矩阵A的列空间的秩 R a n k ( A ) R a n k ( A T ) r (1) Rank(A)Rank(A^T)r\tag{1} Rank(A)Rank(AT)r(1) A X 0 ; A T X …

EFCore_创建项目

添加依赖 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Tools(Migration工具) 根据使用的DB添加对应依赖&#xff1a; SQL Server&#xff1a;Microsoft.EntityFrameworkCore.SqlServer 添加该依赖时可不添加Microsoft.EntityFrameworkCore&#xff0c;该依…