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

<!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>

相关推荐
不一样的故事12637 分钟前
芯片设计是一个高度复杂、分工精细的系统工程
数据结构·经验分享
郭wes代码1 小时前
纯 CSS+JS 实战:手搓一张支持自定义的通用金色电子奖状(万字详细拆解)
前端·javascript·css
阿黎梨梨2 小时前
React 表单处理与性能优化:从入门到进阶
前端·react.js
Whbbit19992 小时前
发布自己的 shadcn-vue 扩展组件,并支持 CLI 安装
前端·开源
Tian_Hang2 小时前
Vue3 父子组件通讯
前端·javascript·vue.js
breeze jiang2 小时前
React memo、useCallback 与 useMemo:父组件多状态时如何减少无效渲染
前端·javascript·react.js
小黑技术栈2 小时前
Java前端基础到入门——16day
java·开发语言·前端
NoteStream2 小时前
【C语言基础】分支和循环(上)
c语言·开发语言·c++·经验分享·笔记·算法·c#
朱涛的自习室3 小时前
从 Prompt 到 Graph:AI 工程的进化史
android·前端·人工智能
大明王朝举重冠军3 小时前
自顶向下建模之建模后的模型检验
经验分享