一道前端经典面试题,前端异步请求并发限流,主要需求是:一次最多有 max 个请求发出,如果有超出的请求待有请求响应完成后再开始继续请求,始终保持仅有 max 个,假设 max=10个,代码如下:
主要原理为:令牌桶原理
// 原理,使用令牌桶
// 指 一次允许同时发出 max 个请求,这max个请求按执行时间返回具体结果,这 max 个有一个返回结果后,再开始执行一个
// 创建一个异步执行任务
function createTask(i) {
return () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(i);
}, i * 100);
});
};
}
// 任务队列类
class TaskQueue {
constructor(max) {
this.max = max || 10; // 当前可执行的任务数
this.taskList = []; // 当前需要执行的任务列表
}
// 添加任务
addTask(task) {
this.taskList.push(task);
}
// 开始任务
startTask() {
setTimeout(() => {
this.run();
}, 0);
}
// 执行任务
run() {
console.log("this.max", this.max);
const length = this.taskList.length;
// 如果当前没有任务需要执行,则直接退出
if (!length) {
return;
}
// 取当前可执行的任务数与当前还剩的任务数的最小值,避免没任务执行但是还进行遍历的浪费
const min = Math.min(this.max, length);
// 遍历当前可执行的任务数
for (let i = 0; i < min; i++) {
// 开始占用一个任务空间,所以可执行的总任务数要减一
this.max--;
// 获取任务列表中的第一个任务,并将第一个任务从列表中删除
const task = this.taskList.shift();
// 以下为异步请求
task()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {
// 释放一个任务空间,所以可执行的总任务数要加一
this.max++;
// 一个请求执行结束,则释放出一个可执行的任务空间,继续调用 run 方法,遍历可执行的任务数,执行其他任务
this.run();
});
}
}
}
const taskQueue = new TaskQueue();
for (let i = 0; i < 32; i++) {
const task = createTask(i);
taskQueue.addTask(task);
}
taskQueue.startTask();
代码参考链接:https://www.bilibili.com/video/BV1XZ4y1y7BX?spm_id_from=333.337.search-card.all.click