前端大批量并发请求的处理

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>测试大批量并发异步请求</title>

</head>

<body>

<script>

const limitFn = (limit) => {

// 这两个变量相对于下面函数执行是闭包 局部全局变量

// 存储promise异步的任务队列

const queue = \[\];

// 用于标记当前队列里Item个数

let activeCount = 0;

// 逐步释放队列任务

const next = () => {

activeCount--;

if (queue.length > 0) {

queue.shift()();

}

};

// 执行器

const run = async (fn, resolve, reject, ...args) => {

// 每次加入一个任务就+1

activeCount++;

// 这里 fn(...args)返回一个Promise

try {

const res = await fn(...args);

// 每一个任务都有独自的resolve将执行结果吐出去

resolve(res);

} catch (err) {

// 这里将报错函数抛出去 以便再次执行

reject(fn)

}

// 每执行完一个任务 就从队列中再释放一个出来执行

next();

};

const enqueue = (fn, resolve, reject, ...args) => {

/*

run.bind 既能把实施参数传进函数内又不立即执行 并返回一个新的函数

将新函数放进去任务队列 暂不执行

*/

queue.push(run.bind(null, fn, resolve, reject, ...args));

// 如果任务队列数量小于限制数量且任务队列有任务则 出队一个任务执行

// 如果进队列的速度大于某个任务执行过程 则会限流执行 但会加进任务队列中等待执行 相当于并发执行的数量始终控制在limit内

if (activeCount < limit && queue.length > 0) {

queue.shift()();

}

};

// 返回最终结果promise

const generator = (fn, ...args) =>

new Promise((resolve, reject) => {

enqueue(fn, resolve, reject, ...args);

});

return generator;

};

let runWay = limitFn(5);

/* 模拟并发异步请求 100条 */

let workNum = 100;

// 异步函数list

let asyncFnList = \[\];

// 并发请求完的结果list

let resultList = \[\];

// 报错后的报错异步请求list

let errorList = \[\];

// 模拟请求

let fakeFn = () => {

return new Promise((resolve, reject) => {

let time = Math.random() * 1000

setTimeout(() => {

resolve(time)

}, time);

})

}

// 异步任务进队列

for (let i = 0; i < workNum; i++) {

asyncFnList.push(fakeFn)

}

const isFinished = () => (resultList.length + errorList.length) == workNum

const doNotifi = () => {

console.log('所有异步任务都执行完:' + JSON.stringify(resultList))

}

// 模拟并发100条请求

asyncFnList.forEach(async fn => {

try {

let res = await runWay(fn);

console.log('单个异步任务执行完:' + res)

resultList.push(res);

// 判断是否所有异步任务都执行完毕

isFinished() && doNotifi()

} catch (errorFn) {

errorList.push(errorFn)

}

})

// 如果有报错异步任务 则重新执行

// TODO 这里可以对报错超过3次的异步任务进行剔除

while (errorList.length > 0) {

try {

let res = runWay(errorList.shift());

resultList.push(res);

// 判断是否所有异步任务都执行完毕

isFinished() && doNotifi()

} catch (errorFn) {

errorList.push(errorFn)

}

}

</script>

</body>

</html>

相关推荐
cszn20261 小时前
AI如何自动识别智能评审废标风险?智能评审项目实践
经验分享
一拳不是超人1 小时前
一个没测暗色模式的 Bug,吃掉了我一半 谷歌扩展用户
前端·javascript·程序员
弘毅 失败的 mian1 小时前
数组和指针基础
c语言·开发语言·经验分享·笔记
liangshanbo12151 小时前
React useState 函数式更新面试题整理
前端·react.js·前端框架
涛涛ing1 小时前
为什么你的页面在 Safari 上总出问题?Interop 2027 正在解决这个 20 年老毛病
前端
不一样的少年_1 小时前
WebP 压缩到底在干嘛?小白也能看懂的原理拆解
前端·后端·图片资源
问心无愧05131 小时前
ctf show web 177
前端·笔记
不一样的少年_2 小时前
PNG/JPG 如何变成 WebP?真相不是改后缀!
前端·后端·图片资源
杉氧2 小时前
RN 性能调优指南:重渲染(Re-renders)控制与长列表(FlatList)优化
android·前端·react native
一_个前端2 小时前
[JS] 一站式搞定 PDF、图片、Dom弹窗、表格的浏览器打印功能
前端