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

Node.js 异步流控制

目录

1、简介

2、状态管理

3、控制流

3.1、串联

3.2、完全并行

3.3、有限并行


1、简介

在其核心,JavaScript被设计为在“主”线程上是非阻塞的,这是呈现视图的位置。你可以想象这在浏览器中的重要性。例如,当主线程被阻塞时,会导致最终用户害怕的臭名昭著的“冻结”,并且无法调度其他事件,最终,导致数据丢失。

这就产生了一些只有函数式编程能解决的独特约束。然而,在更复杂的过程中,回调可能会变得很难处理。这通常会导致“回调地狱”,其中带有回调的多个嵌套函数使代码在读取、调试、组织等方面更具挑战性。

例如:

async1(function (input, result1) {async2(function (result2) {async3(function (result3) {async4(function (result4) {async5(function (output) {// do something with output});});});});
});

当然,在现实生活中,很可能会有额外的代码行来处理result1、result2等,因此,这个问题的长度和复杂性通常会导致代码看起来比上面的例子混乱得多。

这就是函数的用武之地。更复杂的操作由许多功能组成:

  1. 调用方式 input
  2. 中间件
  3. 终止器

“调用方式 input”是对列中的第一个函数。此功能将接受操作的原始输入(如果有)。操作是一系列可执行的功能,原始输入主要是:

  1. 全局环境中的变量
  2. 带参数或不带参数的直接调用
  3. 通过文件系统或网络请求获得的值

网络请求可以是由外部网络、同一网络上的另一应用程序或同一网络或外部网络上的应用程序本身发起的传入请求。

中间件函数将返回另一个函数终止器函数将调用回调。以下说明了网络或文件系统请求的流程。这里的延迟是0,因为所有这些值都在内存中可用。

function final(someInput, callback) {callback(`${someInput} and terminated by executing callback `);
}
function middleware(someInput, callback) {return final(`${someInput} touched by middleware `, callback);
}
function initiate() {
const someInput = 'hello this is a function ';middleware(someInput, function (result) {console.log(result);// requires callback to `return` result});
}
initiate();

2、状态管理

函数可能与状态相关,也可能不与状态相关。当函数的输入或其他变量依赖于外部函数时,就会产生状态依赖性。

通过这种方式,有两种主要的状态管理策略:

  1. 将变量直接传递给函数
  2. 从缓存、会话、文件、数据库、网络或其他外部源获取变量值。

注意,我没有提到全局变量。用全局变量管理状态通常是一种草率的反模式,这使得很难或不可能保证状态。在可能的情况下,应避免使用复杂程序中的全局变量。

3、控制流

如果一个对象在内存中可用,则可以进行迭代,并且不会对控制流进行更改:

function getSong() {let _song = '';let i = 100;for (i; i > 0; i -= 1) {_song += `${i} beers on the wall, you take one down and pass it around, ${i - 1} bottles of beer on the wall\n`;if (i === 1) {_song += "Hey let's get some more beer";}}return _song;
}
function singSong(_song) {if (!_song) throw new Error("song is '' empty, FEED ME A SONG!");console.log(_song);
}
const song = getSong();
// this will work
singSong(song);

但是,如果数据在内存中不存在,则迭代将停止:

function getSong() {let _song = '';let i = 100;for (i; i > 0; i -= 1) {/* eslint-disable no-loop-func */setTimeout(function () {_song += `${i} beers on the wall, you take one down and pass it around, ${i - 1} bottles of beer on the wall\n`;if (i === 1) {_song += "Hey let's get some more beer";}}, 0);/* eslint-enable no-loop-func */}return _song;
}
function singSong(_song) {
if (!_song) throw new Error("song is '' empty, FEED ME A SONG!");
console.log(_song);
}
const song = getSong('beer');
// this will not work
singSong(song);
// Uncaught Error: song is '' empty, FEED ME A SONG!

为什么会发生这种情况?setTimeout指示CPU将指令存储在总线上的其他位置,并指示将数据安排为稍后处理。在函数在0毫秒标记处再次命中之前,经过了数千个CPU周期,CPU从总线中获取指令并执行它们。唯一的问题是song(“”)在数千个循环之前被返回。

在处理文件系统和网络请求时也会出现同样的情况。主线程不能在不确定的时间段内被阻塞——因此,我们使用回调来以可控的方式及时调度代码的执行。

我们可以使用以下3种模式执行几乎所有的操作:

3.1、串联

函数将以严格的顺序执行,这一顺序与循环最相似。

// operations defined elsewhere and ready to execute
const operations = [{ func: function1, args: args1 },{ func: function2, args: args2 },{ func: function3, args: args3 },
];
function executeFunctionWithArgs(operation, callback) {
// executes function
const { args, func } = operation;func(args, callback);
}
function serialProcedure(operation) {if (!operation) process.exit(0); // finishedexecuteFunctionWithArgs(operation, function (result) {// continue AFTER callbackserialProcedure(operations.shift());});
}
serialProcedure(operations.shift());

3.2、完全并行

用于同时运行异步任务

let count = 0;
let success = 0;
const failed = [];
const recipients = [{ name: 'Bart', email: 'bart@tld' },{ name: 'Marge', email: 'marge@tld' },{ name: 'Homer', email: 'homer@tld' },{ name: 'Lisa', email: 'lisa@tld' },{ name: 'Maggie', email: 'maggie@tld' },
];function dispatch(recipient, callback) {// `sendEmail` is a hypothetical SMTP clientsendMail({subject: 'Dinner tonight',message: 'We have lots of cabbage on the plate. You coming?',smtp: recipient.email,},callback);
}function final(result) {console.log(`Result: ${result.count} attempts \& ${result.success} succeeded emails`);if (result.failed.length)console.log(`Failed to send to: \\n${result.failed.join('\n')}\n`);
}recipients.forEach(function (recipient) {dispatch(recipient, function (err) {if (!err) {success += 1;} else {failed.push(recipient.name);}count += 1;if (count === recipients.length) {final({count,success,failed,});}});
});

3.3、有限并行

一种异步、并行、并发受限的循环,例如成功地向10E7用户列表中的1000000个收件人发送电子邮件。

let successCount = 0;
function final() {console.log(`dispatched ${successCount} emails`);console.log('finished');
}
function dispatch(recipient, callback) {
// `sendEmail` is a hypothetical SMTP client
sendMail({subject: 'Dinner tonight',message: 'We have lots of cabbage on the plate. You coming?',smtp: recipient.email,},callback
);
}
function sendOneMillionEmailsOnly() {
getListOfTenMillionGreatEmails(function (err, bigList) {if (err) throw err;function serial(recipient) {if (!recipient || successCount >= 1000000) return final();dispatch(recipient, function (_err) {if (!_err) successCount += 1;serial(bigList.pop());});}serial(bigList.pop());});
}
sendOneMillionEmailsOnly();

相关文章:

Node.js 异步流控制

目录 1、简介 2、状态管理 3、控制流 3.1、串联 3.2、完全并行 3.3、有限并行 1、简介 在其核心,JavaScript被设计为在“主”线程上是非阻塞的,这是呈现视图的位置。你可以想象这在浏览器中的重要性。例如,当主线程被阻塞时&#xff0…...

掌握这些思维技巧,解救996的打工人!

你身边有没有这样的人:面对堆积如山的工作、随时弹出的任务,接二连三的群也能游刃有余地处理。回看自己,旧的任务还在做,新的任务已经从天而降,日程表上满是任务却无从下手…… 明明忙个不停却成果甚微,这…...

【嵌入式Linux】MBR分区表 和 GPT分区表

文章目录 GUID以及分区表MBR分区方案GPT 分区方案GPT分区表结构 GPT分区表LBALBA0(MBR兼容部分)LBA1LBA 2-33python生成GPT分区表gpt分区表实例 gpt分区表查看查看百问网T113-s3固件查看友善之臂nanopi-m1-plus官方固件查看荣品RV1126固件查看f1c200s固件…...

【华为OD机试真题】MVP争夺战(python)100%通过率 超详细代码注释 代码解读

【华为OD机试真题 2022&2023】真题目录 @点这里@ 【华为OD机试真题】信号发射和接收 &试读& @点这里@ 【华为OD机试真题】租车骑绿道 &试读& @点这里@ MVP争夺战 知识点DFS搜索 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 在星球争霸篮球赛对…...

实战打靶集锦-019-BTRSys2.1

提示:本文记录了博主的一次普通的打靶经历 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 FTP服务探查4.2 Apache服务探查4.2.1 wpscan扫描4.2.2 Metasploit神器4.2.3 手工探查页面4.2.3.1 Appearance Editor4.2.3.2 Plugins Editor 5. 提权5.1 系统信息枚…...

2023中国(苏州)国际电源工业展览会暨高端论坛

时间:2023年11月9~11日 地点:苏州国际博览中心 30000㎡展出面积 500参展商 50000名专业观众 中国电源行业风向标----相约苏州,共襄盛举! ◆展会背景Exhibition background: …...

基于SpringBoot+Vue的校园疫情防控系统(附源码和数据库)

文章目录 第一章2.主要技术第三章第四章 系统设计4.1功能结构4.2 数据库设计4.2.1 数据库E/R图4.2.2 数据库表 第五章 系统功能实现5.1系统功能模块5.2后台功能模块5.2.1管理员功能 源码咨询 第一章 springboot校园疫情防控系统演示录像2022 一个好的系统能将校园疫情防控的管理…...

Docker启动安装nacos

当需要在本地或云环境中部署和管理微服务时,Nacos是一个非常流行的选择。Nacos是一个用于动态服务发现、配置管理和服务管理的开源平台。在本文中,我们将详细介绍如何使用Docker来启动和安装Nacos。 步骤1:安装Docker 首先,确保…...

FastDFS总结

目录 概述 什么是分布式文件系统 核心概念 目录结构 上传机制 下载机制 Linux中搭建FastDFS 常用指令 SpringBoot整合FastDFS FastDFS集成Nginx 概述 FastDFS是一个开源的轻量级分布式文件系统。它解决了大数据量存储和负载均衡等问题。特别适合以中小文件&#xff…...

【职场新人备忘录】新人职场生存指南:快速适应、持续成长和个人提升

新人职场生存指南:快速适应、持续成长和个人提升 引言 职场对于新人来说充满了新的挑战和机遇。作为一名新人,如何在职场中快速适应、获得成长和提升自己是至关重要的技能。本备忘录旨在为职场新人提供实用的职场tips,帮助他们在职场中取得…...

SpringCloud Alibaba详解

目录 微服务架构概念 服务治理 服务调用 服务网关 服务容错 链路追踪 SpringcloudAlibaba组件 Nacos 负载均衡 Ribbon Fegin Sentinel 高并发测试 容错方案 Sentinel入门 Feign整合Sentinel 微服务架构概念 服务治理 服务治理就是进行服务的自动化管理&#xf…...

Golang每日一练(leetDay0065) 位1的个数、词频统计

目录 191. 位1的个数 Nnumber of 1-bits 🌟 192. 统计词频 Word Frequency 🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 191. 位1的个数 Nnum…...

前端技术搭建井字游戏(内含源码)

The sand accumulates to form a pagoda ✨ 写在前面✨ 功能介绍✨ 页面搭建✨ 样式设置✨ 逻辑部分 ✨ 写在前面 上周我们实通过前端基础实现了飞机大战游戏,今天还是继续按照我们原定的节奏来带领大家完成一个井字游戏游戏,功能也比较简单简单&#x…...

视频截取gif方法分享,利用gif制作工具在线制作动图

表情包作为聊天社交中调节氛围的工具,而动态的gif表情包更是深受大众的喜爱。那么,这种gif动态图片要怎么制作呢?其实,很简单不需要下载软件,小白也能轻松操作的。 一、什么工具能够制作gif动画呢? 使用G…...

VRRP高级特性——管理VRRP

目录 管理VRRP备份组与业务VRRP备份组 管理VRRP备份组的两种实现方式 配置管理备份组 当在设备上配置了多个VRRP备份组时,为了减少设备间交互大量的VRRP协议报文,可以将其中一个VRRP备份组配置为管理VRRP备份组(mVRRP)&#xf…...

FreeRTOS内核:详解Task各状态(GPT4帮写)

FreeRTOS内核:详解Task各状态(GPT4帮写) 1. 背景2. Task顶层状态区分3. 运行状态(Running)4. 非运行状态4.1 阻塞态(Blocked):4.2 挂起态(Suspended)4.3 就绪…...

基于粒子群优化算法的最佳方式优化无线传感器节点的位置(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 此代码优化了由于电池耗尽而产生覆盖空洞后 WSN 节点的位置。如果活动通信中的任何节点死亡,则通过PSO优化再次定位…...

第一章 Andorid系统移植与驱动开发概述 - 读书笔记

Android驱动月考1 第一章 Andorid系统移植与驱动开发概述 - 读书笔记 1.Android系统的架构: (1)Linux内核,Android是基于Linux内核的操作系统,并且开源,所以Android与Ubuntu等操作系统的差别很小&#x…...

vi编辑器的三种模式及其对应模式下常用指令

vi是Linux系统的第一个全屏幕交互式编辑工具,在嵌入式的 学习中是一个不可或缺的强大的文本编辑工具。 一、三种模式 命令模式 如何进入命令模式:按esc键 复制:yy nyy(n:行数) 删除(剪切): dd ndd 粘贴:p 撤销&…...

webpack: 5 报错,错误

webpack-报错:Uncaught ReferenceError: $ is not defined (webpack) webpack打包jquery的插件(EasyLazyLoad)时,报错 方法一: //多个js文件用到jquery,用这种方法 在jquery.min.js的做最后写上下面的代码…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...