前端如何并发控制

本文节选自我的博客:前端如何并发控制

  • 💖 作者简介:大家好,我是MilesChen,偏前端的全栈开发者。
  • 📝 CSDN主页:爱吃糖的猫🔥
  • 📣 我的博客:爱吃糖的猫
  • 📚 Github主页: MilesChen
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 💬介绍:The mixture of WEB+DeepLearning+Iot+anything🍁

前言

众所周知,Promise处理异步任务能避免他们阻塞程序执行。当一次并发大量异步任务会导致内存消耗过大、程序阻塞等问题。本文带大家实现异步任务控制器,限制并发异步任务数量,来解决高并发问题。
假设一个场景:有20个异步任务,每次只能处理三个异步任务,要求尽可能快速的拿到处理结果。
下面带来分段Promise.all异步任务控制器两种实现方案。

Promise.all

暴力Promise.all

最简单的方式就是Promise.all,一次并发20个任务,没有使用异步任务控制,简单、粗暴。

// 模拟请求 随机产生100-500ms延时
function randomRequest(url){return new Promise((resolve)=>{let delay = Math.floor(Math.random()*400+100)setTimeout(()=>{resolve({state:'success',data:{url}})},delay)})
}
async function main(){const queue = [];for (let i = 1; i <= 20; i++) {queue.push(randomRequest(`https://xxx.xx/api/${i}`));}let a = await Promise.all(queue)console.log(a);
}
mian()

分段Promise.all

这种分段的方式,有两个显著的缺陷:

  1. 阻塞问题:因为程序每次都要等异步任务全执行完,才进行下个异步任务,其中一个异步任务发生阻塞则会导致整体阻塞。
  2. 无法处理reject: 一旦有一个 Promise 被拒绝就立即返回拒绝的 Promise,并不会等待其他 Promise 的解析结果
// 模拟请求 随机产生100-500ms延时
function randomRequest(url){return new Promise((resolve)=>{let delay = Math.floor(Math.random()*400+100)setTimeout(()=>{resolve({state:'success',data:{url}})},delay)})
}
async function main(maxNum){const queue = [];for (let i = 1; i <= 20; i++) {queue.push(randomRequest(`https://xxx.xx/api/${i}`));}for(let i=0;i<Math.ceil(queue.length/maxNum);i++){let a = await Promise.all(queue.slice(i*maxNum,i*maxNum+maxNum))console.log(a);}
}
main(3)

异步任务控制器

开始就并发3个数量的一次任务,当一个异步任务处理完成,接龙下个异步任务,就像3条流水线并行。解决了Promise.all带来的阻塞问题和无法处理reject问题。
实现需要注意:

  • urls的长度为0时,results就没有值,此时应该返回空数组
  • maxNum大于urls的长度时,应该取的是urls的长度,否则则是取maxNum
  • 需要定义一个count计数器来判断是否已全部请求完成
  • 因为没有考虑请求是否请求成功,所以请求成功或报错都应把结果保存在results集合中
  • results中的顺序需和urls中的保持一致
// 模拟请求 0.5概率成功,随机产生100-500ms延时
function randomRequest(url){return new Promise((resolve,reject)=>{let delay = Math.floor(Math.random()*400+100)setTimeout(()=>{let rand = Math.random()if(rand>0.5) resolve({state:'success',data:{url}})else reject({state:'error'}) },delay)})}// 并发控制函数
const controlAsync = (urls, maxNum) => {return new Promise((resolve) => {if (urls.length === 0) {resolve([]);return;}const results = [];let index = 0; // 下一个请求的下标let count = 0; // 当前请求完成的数量// 发送请求async function request() {if (index === urls.length) return;const i = index; // 保存序号,使result和urls相对应const url = urls[index];index++;console.log(url);try {const resp = await randomRequest(url);// resp 加入到resultsresults[i] = resp;} catch (err) {// err 加入到resultsresults[i] = err;} finally {count++;// 判断是否所有的请求都已完成if (count === urls.length) {console.log('完成了');resolve(results);}request();}}// maxNum和urls.length取最小进行调用const times = Math.min(maxNum, urls.length);for(let i = 0; i < times; i++) {request();}})
}const urls = [];
for (let i = 1; i <= 20; i++) {urls.push(`https://xxx.xx/api/${i}`);
}
controlAsync(urls, 3).then(res => {console.log(res);
})

总结

异步任务控制器Promise.all实现复杂一些,但能解决阻塞问题和reject问题;
在工作中可以将异步任务控制器封装成通用的工具函数,实现多种异步任务的并发控制。


感谢小伙伴们的耐心观看,本文为笔者个人学习记录,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

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

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

相关文章

2023年人工智能技术与智慧城市发展白皮书

人工智能与智慧城市是当前热门的话题和概念&#xff0c;通过将人工智能技术应用在城市管理和服务中&#xff0c;利用自动化、智能化和数据化的方式提高城市运行效率和人民生活质量&#xff0c;最终实现城市发展的智慧化&#xff0c;提升城市居民的幸福感。 AI技术在城市中的应…

QT中使用ffmpeg的api进行视频的播放

在了解ffmpeg使用api进行视频的播放之前&#xff0c;我们首先了解一下视频的播放流程。 一、视频的播放流程 首先是我们最常见的视频文件&#xff0c;在播放流程中首先是要打开视频文件&#xff0c;将视频文件中的数据进行解封装&#xff0c;之后再将解封装之后的视频进行解码…

【C#学习笔记】引用类型(2)

文章目录 ObjectEqualsGetTypeToStringGetHashCode string逐字文本复合格式字符串字符串内插 StringBuilderStringBuilder 的工作原理StringBuilder提供的方法访问字符迭代字符查询字符 dynamic Object 支持 .NET 类层次结构中的所有类&#xff0c;并为派生类提供低级别服务。…

【docker】docker镜像原理

目录 一、操作系统组成部分二、Linux文件系统三、docker镜像原理四、说明五、镜像制作5.1 方式一&#xff1a;容器转镜像5.2 方式二&#xff1a;dockerfile5.2.1 dockerfile说明5.2.2 dockerfile关键字 一、操作系统组成部分 1.进程调度子系统 2.进程通信子系统 3.内存管理子系…

Python实现GA遗传算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;最早是由美国的 John holland于20世…

实战 02|「可点击图片」

前言 实践是最好的学习方式&#xff0c;技术也如此。 文章目录 前言一、功能需求&#xff08;一&#xff09;1、功能需求描述 一、功能需求&#xff08;一&#xff09; 1、功能需求描述 用户可以点击图片来执行相应的操作&#xff08;显示 Toast 信息&#xff09;&#xff1b;…

全面解析大语言模型的工作原理

当ChatGPT在去年秋天推出时&#xff0c;在科技行业乃至世界范围内引起了轰动。当时&#xff0c;机器学习研究人员尝试研发了多年的语言大模型&#xff08;LLM&#xff09;&#xff0c;但普通大众并未十分关注&#xff0c;也没有意识到它们变得多强大。 如今&#xff0c;几乎每个…

无代码开发(BIP旗舰版-YonBuilder)

目录 我的应用 新建领域 菜单管理 应用构建 新建应用 对象建模 新增业务对象 新增业务实体 页面建模 新增页面 编辑页面 发布管理 我的应用 角色管理 yonbuilder开发平台&#xff0c;提供标准服务和专业开发服务&#xff1b; 本篇文章只演示标准服务的可视化应用…

new一个构造函数

new 一个构造函数发生了什么&#xff1f; new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 new 关键字会进行如下的操作&#xff1a; 1.创建一个空的简单 JavaScript 对象&#xff0c;即{}&#xff1b; 2.链接该对象到另一个对象(即设置该对象…

Flink State 和 Fault Tolerance详解

有状态操作或者操作算子在处理DataStream的元素或者事件的时候需要存储计算的中间状态&#xff0c;这就使得状态在整个Flink的精细化计算中有着非常重要的地位&#xff1a; 记录数据从某一个过去时间点到当前时间的状态信息。以每分钟/小时/天汇总事件时&#xff0c;状态将保留…

【C++】基础练习(一)||从C到C++函数

C基础练习&#xff08;一&#xff09; 从C 到C函数 从C 到C ⭐️C是在C语言基础山改进发展而来的&#xff0c;是C语言的一个超集。 1.关于C语言和C的关系&#xff0c;以下说法正确的是&#xff1a;A A.C兼容C语言 B.C语言部分兼容C C.C部分兼容C语言 D.C语言兼容C 分析&#x…

调整图片中的人物头像的位置(裁剪图片的时候)

其实调整图片的适应边框的属性 我们首先会想到 object-fit object-fit CSS 属性指定可替换元素&#xff08;例如&#xff1a; 或 &#xff09;的内容应该如何适应到其使用高度和宽度确定的框。 contain 被替换的内容将被缩放&#xff0c;以在填充元素的内容框时保持其宽高比…

弹性布局,网格布局,JavaScript

弹性盒子布局&#xff08;Flexbox Layout&#xff09;&#xff1a;通过display: flex;设置容器为弹性盒子&#xff0c;可以实现更复杂的自适应和响应式布局。 网格布局&#xff08;Grid Layout&#xff09;&#xff1a;通过display: grid;设置容器为网格布局&#xff0c;可以将…

Unity 引擎做残影效果——2、屏幕后处理方式

Unity实现残影效果 大家好&#xff0c;我是阿赵。 这里继续介绍Unity里面做残影的方法。之前介绍了BakeMesh的方法做残影&#xff0c;这一期介绍的是用屏幕后处理的方法做残影。 一、原理 之前的BakeMesh方法&#xff0c;是真的生成了很多个网格模型在场景里面。如果用后处理做…

day49-Springboot

Springboot 1. Springboot简介 1.1 简介&#xff1a;Springboot来简化Spring应用开发的一个框架&#xff0c;约定大于配置 1.2 优点&#xff1a; 可以快速的构建独立运行的Spring项目&#xff1b; 框架内有Servlet容器&#xff0c;无需依赖外部&#xff0c;所以不需要达成w…

正则匹配img标签里面src

正则&#xff1a; (?<src\s*\s*\")\S(?\"{1})匹配效果&#xff1a;

Ansible —— playbook 剧本

Ansible —— playbook 剧本 一、playbook的概述1.playbook简介2.什么是Ansible playbook剧本&#xff1f;3.Ansible playbook剧本的特点4.如何使用Ansible playbook剧本&#xff1f;5.playbooks 本身由以下各部分组成 二、playbook示例1.运行playbook2.定义、引用变量3.指定远…

HarmonyOS/OpenHarmony元服务开发-卡片使用动效能力

ArkTS卡片开放了使用动画效果的能力&#xff0c;支持显式动画、属性动画、组件内转场能力。需要注意的是&#xff0c;ArkTS卡片使用动画效果时具有以下限制&#xff1a; 以下示例代码实现了按钮旋转的动画效果&#xff1a; Entry Component struct AttrAnimationExample { St…

Vue axios + Vue使用

相对于原生的阿贾克斯&#xff0c;axios提供的方法使用起来会更加的简便&#xff0c;之前网络数据获取到了&#xff0c;如何和vue一起使用呢&#xff1f; 网络应用的核心就是data中的数据一部分是通过网络获取到的。所以在方法当中发起网络请求&#xff0c;在响应回来之后将服…

mac切换jdk版本

查询mac已有版本 1、打开终端&#xff0c;输入&#xff1a; /usr/libexec/java_home -V注意&#xff1a;输入命令参数区分大小写(必须是-V) 2.目前本地装有两个版本的jdk xxxxedydeMacBook-Pro-9 ~ % /usr/libexec/java_home -V Matching Java Virtual Machines (2):20.0.1 (…