当前位置: 首页 > news >正文

Node.js 事件循环:定时任务、延迟任务和 I/O 事件的艺术

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6
🍨 阿珊和她的猫_CSDN个人主页
🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • 定时器和延时器
    • 使用 setTimeout 和 setInterval 实现定时任务
    • 解释定时器和延时器在事件循环中的工作原理
  • I/O 事件
    • 文件操作和网络请求等 I/O 事件的处理
    • 理解 I/O 事件在事件循环中的优先级和回调函数的执行时机
  • 拓展话题:Promise 和 Async/Await
    • 介绍 Promise 和 Async/Await 与事件循环的关系
    • 如何使用 Promise 和 Async/Await 优化事件循环的性能
  • 总结与展望
    • 总结 Node.js 事件循环的核心概念和工作原理

定时器和延时器

使用 setTimeout 和 setInterval 实现定时任务

在 Node.js 中,你可以使用 setTimeoutsetInterval 函数来实现定时任务。
这两个函数都接受一个回调函数作为参数,并在指定的时间后执行该回调函数。

以下是使用 setTimeoutsetInterval 实现定时任务的示例代码:

// 使用 setTimeout 实现定时任务
setTimeout(() => {console.log('定时任务执行');
}, 1000); // 1000 毫秒后执行回调函数// 使用 setInterval 实现定时任务
setInterval(() => {console.log('每隔 1 秒执行定时任务');
}, 1000); // 每隔 1 秒执行回调函数

在上面的示例中,我们使用 setTimeout 函数设置了一个定时任务,它将在 1 秒后执行。然后,我们使用 setInterval 函数设置了一个每隔 1 秒执行一次的定时任务。

请注意,setTimeoutsetInterval 函数返回一个定时器标识符,你可以使用这个标识符来取消定时任务。例如:

let timerId = setTimeout(() => {console.log('定时任务执行');
}, 1000);clearTimeout(timerId); // 取消定时任务

在上面的示例中,我们使用 clearTimeout 函数取消了之前设置的定时任务。同样,你也可以使用 clearInterval 函数来取消 setInterval 设置的定时任务。

解释定时器和延时器在事件循环中的工作原理

定时器(setTimeoutsetInterval)和延时器(setImmediatesetTimeout函数的第二个参数)在事件循环中以不同的方式工作。

  1. setTimeoutsetInterval:这两个函数将回调函数添加到定时器事件队列(timers)中。当事件循环到达 timers 阶段时,它会按照到期时间的顺序执行回调函数。

    • setTimeout 函数接受两个参数:回调函数和延迟时间(以毫秒为单位)。它将回调函数添加到定时器事件队列中,并在指定的延迟时间后执行。
    • setInterval 函数与 setTimeout 类似,除了它会在每次回调函数执行后重新将其添加到定时器事件队列中,以实现周期性执行。
  2. setImmediate:这个函数将回调函数添加到 setImmediate 队列中。setImmediate 队列中的回调函数会在事件循环的 check 阶段被执行,并且在 timers 队列之前。

    • setTimeout 不同,setImmediate 的回调函数会在当前事件循环迭代中尽快执行,而不是在特定的延迟时间后执行。

    • 由于 setImmediate 队列在 timers 队列之前执行,因此如果同时使用 setTimeoutsetImmediatesetImmediate 队列中的回调函数会先执行。

需要注意的是,setImmediate 并不是在所有环境中都被支持,它是 Node.js 中的一个扩展,而在浏览器环境中不被支持。在浏览器中,可以使用 Promisethen 方法或 MutationObserver 来实现类似的立即执行功能。

I/O 事件

文件操作和网络请求等 I/O 事件的处理

文件操作和网络请求等 I/O 事件的处理在事件循环中通过 I/O 事件队列(I/O)进行处理。

当进行文件操作或发起网络请求时,Node.js 会将相应的 I/O 事件添加到 I/O 事件队列中。

事件循环会在 I/O 阶段检查 I/O 事件队列是否有事件。如果有事件,事件循环会从队列中取出事件并执行相应的回调函数。在文件操作中,例如读取文件或写入文件,回调函数将在文件操作完成后被执行。在网络请求中,例如 HTTP 请求,回调函数将在响应数据可用时被执行。

I/O 事件的处理是非阻塞的,这意味着在执行 I/O 操作时,事件循环不会被阻塞
相反,它会继续处理其他队列中的事件
当 I/O 操作完成并将事件添加到 I/O 事件队列中时,事件循环会在适当的时候处理这些事件。

这种非阻塞 I/O 模型使得 Node.js 能够高效地处理大量的 I/O 操作,因为它不会因为等待 I/O 操作完成而阻塞事件循环。
相反,它可以同时处理多个 I/O 操作,并在它们完成时逐个处理它们的回调函数。

理解 I/O 事件在事件循环中的优先级和回调函数的执行时机

在事件循环中,I/O 事件的优先级与其他事件队列(如定时器事件队列和 setImmediate 队列)的优先级不同。

具体来说,I/O 事件的优先级较低,它们会在其他事件队列中的事件处理完毕后被处理。

回调函数的执行时机取决于事件的类型和处理方式。对于文件操作和网络请求等 I/O 事件,回调函数将在文件操作完成或响应数据可用时被执行。在文件操作中,例如读取文件或写入文件,回调函数将在文件操作完成后被执行。在网络请求中,例如 HTTP 请求,回调函数将在响应数据可用时被执行。

需要注意的是,I/O 事件的处理是非阻塞的,这意味着在执行 I/O 操作时,事件循环不会被阻塞。相反,它会继续处理其他队列中的事件。当 I/O 操作完成并将事件添加到 I/O 事件队列中时,事件循环会在适当的时候处理这些事件。

这种非阻塞 I/O 模型使得 Node.js 能够高效地处理大量的 I/O 操作,因为它不会因为等待 I/O 操作完成而阻塞事件循环。相反,它可以同时处理多个 I/O 操作,并在它们完成时逐个处理它们的回调函数。

拓展话题:Promise 和 Async/Await

介绍 Promise 和 Async/Await 与事件循环的关系

Promise 和 Async/Await 是 JavaScript 中的异步编程解决方案,它们与事件循环密切相关。

Promise 是一种用于处理异步操作结果的对象。它可以表示一个异步操作的最终完成(fulfillment)或失败(rejection)。Promise 对象有一个 then 方法,用于注册在异步操作完成后执行的回调函数。

在事件循环中,Promise 的处理通过 Promise 队列(promise)进行。当创建一个 Promise 对象时,它会被添加到 Promise 队列中。事件循环会在 Promise 阶段检查 Promise 队列是否有等待处理的 Promise 对象。如果有,事件循环会取出队列中的 Promise 对象并执行其回调函数。

Async/Await 是基于 Promise 的语法糖,它使得异步代码的编写更加简洁和直观。使用 Async/Await,你可以将异步操作编写为类似同步代码的形式,通过使用 async 关键字定义异步函数,并使用 await 关键字等待 Promise 的完成。

在 Async/Await 的情况下,异步操作的执行仍然通过 Promise 进行,但异步函数的执行会被暂停,直到等待的 Promise 对象完成。当遇到 await 关键字时,JavaScript 引擎会将异步函数的执行挂起,并将其添加到微任务队列(microtask)中。事件循环会在 microtask 阶段检查微任务队列,并执行其中的微任务。

因此,Promise 和 Async/Await 都是 JavaScript 中处理异步操作的方式,它们通过事件循环来协调异步操作的执行。Promise 通过 Promise 队列进行处理,而 Async/Await 通过将异步函数的执行挂起并添加到微任务队列中来实现异步操作的等待和处理。事件循环会按照特定的顺序处理这些队列中的事件,以实现异步代码的非阻塞执行。

如何使用 Promise 和 Async/Await 优化事件循环的性能

使用 Promise 和 Async/Await 可以在一定程度上优化事件循环的性能。

以下是一些建议:

在这里插入图片描述

  1. 使用 Promise.all:如果你有多个异步操作需要同时完成,可以使用 Promise.all 方法。它接受一个 Promise 对象数组作为参数,并返回一个新的 Promise 对象,该对象在所有传入的 Promise 对象都完成后才会完成。这样可以避免多个异步操作的回调函数在事件循环中被多次处理,提高性能。

  2. 使用 Async/Await: Async/Await 是基于 Promise 的语法糖,它使得异步代码的编写更加简洁和直观。使用 Async/Await 可以避免回调地狱的问题,并使代码更易于阅读和维护。在使用 Async/Await 时,注意将异步操作放在 async 函数中,并使用 await 关键字等待 Promise 的完成。

  3. 避免嵌套的异步操作:过多的嵌套异步操作可能会导致事件循环的性能下降。尽量保持异步操作的层次结构简单,并避免在回调函数中再次进行异步操作。如果需要处理嵌套的异步操作,可以使用 Promise 的链式调用或使用 async/await 来简化代码。

  4. 使用微任务:在 Async/Await 中,遇到 await 关键字时,JavaScript 引擎会将异步函数的执行挂起,并将其添加到微任务队列中。微任务队列会在事件循环的 microtask 阶段被处理。利用微任务队列可以实现一些性能优化,例如在微任务队列中进行一些轻量级的操作,以避免阻塞事件循环。

  5. 合理使用 Promise 的 resolve 和 reject:在创建 Promise 对象时,尽量避免在 Promise 的构造函数中传入立即 resolve 或 reject 的值。这可能会导致不必要的微任务被添加到微任务队列中,从而影响性能。尽量在需要时才 resolve 或 reject Promise 对象。

通过合理使用 Promise 和 Async/Await,可以使事件循环的性能得到一定程度的优化。但具体的优化效果还需要根据实际情况进行评估和测试,以确保在你的应用中获得最佳性能。

总结与展望

总结 Node.js 事件循环的核心概念和工作原理

Node.js 事件循环的核心概念和工作原理可以总结如下:

  1. 事件循环:Node.js 是基于事件驱动的非阻塞 I/O 模型。事件循环是 Node.js 处理事件的核心机制,它负责监听和处理各种事件,并在需要时执行相应的回调函数。

  2. 事件队列:事件循环使用事件队列来管理事件。有不同类型的事件队列,包括定时器事件队列、I/O 事件队列和 setImmediate 队列。这些队列按照特定的顺序进行处理。

  3. 阶段:事件循环分为多个阶段,包括 timers 阶段、I/O 阶段和 poll 阶段等。每个阶段会处理特定类型的事件。

  4. 回调函数:当事件发生时,相应的回调函数会被添加到事件队列中。事件循环会在适当的阶段取出队列中的回调函数并执行它们。

  5. 非阻塞 I/O:Node.js 使用非阻塞 I/O 模型,这意味着在执行 I/O 操作时,事件循环不会被阻塞。相反,它会将 I/O 操作委托给操作系统,并在 I/O 操作完成后触发相应的事件。

  6. 异步编程:由于 Node.js 的非阻塞特性,异步编程成为常见的编程方式。使用异步函数和回调函数可以在不阻塞事件循环的情况下执行异步操作。

  7. 定时器和延时器:定时器和延时器是在事件循环中管理时间相关操作的重要工具。定时器会在指定的时间后将回调函数添加到定时器事件队列中,而延时器会在当前事件循环迭代结束后将回调函数添加到下一个事件循环迭代的 poll 阶段。

通过事件循环,Node.js 能够高效地处理大量的 I/O 操作和并发请求,提供了一种高效的异步编程模型。了解事件循环的工作原理对于编写高效和可靠的 Node.js 应用至关重要。

相关文章:

Node.js 事件循环:定时任务、延迟任务和 I/O 事件的艺术

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...

陪诊系统:基于自然语言处理的患者沟通创新

医疗领域的数字化转型正日益引入创新技术,其中基于自然语言处理(NLP)的陪诊系统成为提升患者沟通的一项关键技术。本文将深入研究这一领域,介绍陪诊系统如何借助NLP实现患者沟通的创新,并提供一个简单的Python代码示例…...

实用攻略——SD-WAN网络配置步骤详解

SD-WAN(软件定义广域网)作为一种新兴的网络技术,被广泛应用于构建高效、可靠的企业组网。 本文将详细介绍企业组网中SD-WAN涉及的配置过程,并提供一些配置技巧,以帮助企业快速了解企业组网的配置。通过使用SD-WAN技术&…...

​无人机摄影测量

无人机摄影测量技术是传统航空摄影测量手段的有力补充,具有机动灵活、高效快速、精细准确、作业成本低、生产周期短、影像获取空间分辨率高、高危地区探测等优势。无人机与航空摄影测量相结合使得“无人机数字低空遥感”成为航空遥感领域的一个崭新发展方向。无人机…...

对el-select封装成组件使用

效果与直接使用el-select一样&#xff0c;多处用el-select显得代码冗余就进行了封装 效果图&#xff1a; el-select封装&#xff1a; <template><div class"my-select"><el-selectv-model"person.modelValue":placeholder"placehold…...

pytorch 多卡并行训练

目录 设置参数&#xff1a; 训练时参数&#xff1a; 调用命令&#xff1a; 设置参数&#xff1a; import argparseparser argparse.ArgumentParser()parser.add_argument(--batch_size, typeint, default64, helpBatch size for training)parser.add_argument(--local_rank…...

C# Bin、XML、Json的序列化和反序列化

1&#xff09;序列化前的准备 声明类&#xff1a; [Serializable]public class BandItem{//JsonIgnore&#xff1a;当不想把某字段值序列化到Json时使用//[JsonIgnore]public string Name { get; set; }public string MusicStyle { get; set; }public string Masterpiece { ge…...

mediapipe+opencv实现保存图像中的人脸,抹去其他信息

mediapipeopencv MediaPipe本身不提供图像处理功能&#xff0c;它主要用于检测和跟踪人脸、手势、姿势等。如果您想要从图像中仅提取人脸主要信息并去除其他信息. # codingutf-8 """project: teatAuthor&#xff1a;念卿 刘file&#xff1a; test.pydate&…...

clickhouse的向量化执行

背景 clickhouse快的很大一部分原因来源于数据的向量化执行&#xff0c;本文就来看一下向量化执行和正常标量执行的区别 SIMD的向量化执行 从上图可知&#xff0c;clickhouse通过SIMD指令可以做到一个cpu周期操作两个向量的运算操作&#xff0c;比起普通的cpu指令效率提高了N…...

R语言实验三

1、读取一个文件并进行如下操作。 ①使用命令清空工作空间&#xff0c;使用read.table读取exam_1.txt文件&#xff0c;将文件保存到data变量中&#xff0c;数据第一行设置为列名&#xff0c;第一列是行名。 ②判断对象data是否为矩阵。 ③将对象转换为矩阵&#xff0c;记为d…...

springboot-mongodb-连接配置

文章目录 配置Maven依赖URL格式单节点配置示例副本集&#xff08;含连接池配置&#xff09; 配置Maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependenc…...

基于单片机的多功能视力保护器(论文+源码)

1.系统设计 多功能视力保护器在设计过程中能够对用户阅读过程中的各项数据信息进行控制&#xff0c;整体设计分为亮种模式&#xff0c;分别是自动模式&#xff0c;手动模式。在自动模式的控制下&#xff0c;当单片机检测当前光照不强且有人时就开启LED灯&#xff0c;并且会根据…...

如何保护 API 安全

为了收集有关 API 管理当前和未来状态的见解&#xff0c;我们邀请来自 18 家公司的 IT 专业人士分享他们的想法。我们问他们&#xff1a;“哪些技术和工具对于保护 API 最有效&#xff1f;” 他们告诉我们的是&#xff1a; 验证 我们经常向已知的 B2B 合作伙伴提供 API 访问权…...

工业机器视觉megauging(向光有光)使用说明书(十五,轻量级的visionpro)

程序&#xff08;软件&#xff09;的一些不足和建议&#xff1a;&#xff08;后续会跟进&#xff09; 不足&#xff1a;&#xff08;如果你发现了&#xff0c;谢谢及时提出来&#xff09; 1&#xff0c;找线工具有噪点抑制功能&#xff1b;blob跟随工具&#xff0c;匹配跟随工…...

Linux e2fsck命令教程:如何检查和修复文件系统(附案例详解和注意事项)

Linux e2fsck命令介绍 e2fsck是一个用于检查Linux第二扩展文件系统&#xff08;ext2fs&#xff09;的命令。它也支持包含日志的ext2文件系统&#xff0c;这些文件系统有时也被称为ext3文件系统。该命令会自动保存找到的坏块到文件系统中&#xff0c;以便这些硬盘的部分不再被使…...

TypeScript 的安装与使用

npm i typescript -g依赖会安装 tsc 命令 tsc -v初始化 配置 tsc --init生成 tsconfig.json tsconfig.json 配置 要支持 import 模块语法的话 rollup的配置 target 选项需要设置 ES5 module 选项需要改成 es2015 esbuild 的配置 target: ESNext module: ESNext moduleReso…...

Git版本管理配置说明 - Visual Studio

一、 Git服务端配置 在源代码管理服务器新建文件夹,并配置共享访问权限Everyone(读取/写入)。 在本地访问这台服务器共享目录,确保正确打开。 在VS中打开项目,点选Git更改,点击“创建Git仓库”,创建项目初始版本。 弹出如下对话框: 因为我们只是在局域网中开发项…...

Rust语言项目实战(四) - 界面绘制与渲染

回顾 前面的章节中&#xff0c;我们已经完成了下面的工作&#xff1a; 准备所需的音频文件设置游戏所需的屏幕和键盘配置创建了游戏主循环并在其中实现按键Esc或q退出游戏的功能游戏退出前还原配置 目前游戏的界面还是一片空白&#xff0c;本章我们开始为游戏在终端上绘制并…...

动态规划学习——回文串

目录 一&#xff0c;回文子串 1.题目 2.题目接口 3&#xff0c;解题代码及其思路 解题代码&#xff1a; 二&#xff0c; 分割回文串II 1&#xff0c;题目 2&#xff0c;题目接口 3&#xff0c;解题思路及其代码 一&#xff0c;回文子串 1.题目 给你一个字符串 s &…...

优化你的计算机性能:如何根据 CPU 占用率决定硬件升级

优化你的计算机性能&#xff1a;如何根据 CPU 占用率决定硬件升级 一、引言二、CPU 占用率的意义与影响三、监测和评估 CPU 占用率四、判断硬件升级需求的依据五、硬件升级方案和建议六、总结 一、引言 计算机性能优化是提升计算机系统整体效能的过程&#xff0c;它对于用户和…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...