福州网站建设多少钱,wordpress转发插件,欧美网站建设风格特点,wordpress付费查看内容本文节选自我的博客#xff1a;前端如何并发控制 #x1f496; 作者简介#xff1a;大家好#xff0c;我是MilesChen#xff0c;偏前端的全栈开发者。#x1f4dd; CSDN主页#xff1a;爱吃糖的猫#x1f525;#x1f4e3; 我的博客#xff1a;爱吃糖的猫#x1f4d… 本文节选自我的博客前端如何并发控制 作者简介大家好我是MilesChen偏前端的全栈开发者。 CSDN主页爱吃糖的猫 我的博客爱吃糖的猫 Github主页: MilesChen 支持我点赞收藏⭐️留言介绍The mixture of WEBDeepLearningIotanything
前言
众所周知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()*400100)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
这种分段的方式有两个显著的缺陷
阻塞问题因为程序每次都要等异步任务全执行完才进行下个异步任务其中一个异步任务发生阻塞则会导致整体阻塞。无法处理reject 一旦有一个 Promise 被拒绝就立即返回拒绝的 Promise并不会等待其他 Promise 的解析结果
// 模拟请求 随机产生100-500ms延时
function randomRequest(url){return new Promise((resolve){let delay Math.floor(Math.random()*400100)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 i0;iMath.ceil(queue.length/maxNum);i){let a await Promise.all(queue.slice(i*maxNum,i*maxNummaxNum))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()*400100)setTimeout((){let rand Math.random()if(rand0.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问题 在工作中可以将异步任务控制器封装成通用的工具函数实现多种异步任务的并发控制。 感谢小伙伴们的耐心观看本文为笔者个人学习记录如有谬误还请告知万分感谢如果本文对你有所帮助还请点个关注点个赞~您的支持是笔者不断更新的动力