1.任务队列
常规思路,利用队列记录等待执行的异步任务,递归调用执行函数即可
const request = (delay) =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`请求完成: ${delay}s`);
}, delay * 1000);
});
type Task = () => Promise<unknown>;
const controller = (count: number) => {
const taskQue: Task[] = [];
let requestCount = 0;
const run = () => {
if (taskQue.length && requestCount < count) {
const curRequest = taskQue.shift()!;
requestCount += 1;
curRequest().then((res) => {
requestCount -= 1;
console.log(res);
run();
});
}
};
const addTask = (fn: Task) => {
taskQue.push(fn);
run();
};
return {
run,
addTask,
};
};
/* 最多并发2个任务 */
const request4 = controller(2);
console.log("haahaaha");
request4.addTask(() => request(1));
request4.addTask(() => request(1));
request4.addTask(() => request(1));
request4.addTask(() => request(1));
2. 异步函数唤醒队列
当请求大于容量时,利用异步函数的await阻塞异步函数执行,同时将唤醒执行的resolve方法放入等待队列,当有任务完成或失败时调用resolve方法唤醒被阻塞的异步操作
function createAsyncWorker(capacity) {
/* 等待队列 */
const taskQue = [];
let requestCount = 0;
const executor = async (asyncFn) => {
/* 如果请求数大于容量,利用await挂起,将唤醒resolve方法加入队列 */
if (requestCount >= capacity) {
await new Promise((resolve) => taskQue.push(resolve));
}
requestCount += 1;
/* 任务reject时也需要开始下一个任务,此处不能用await,await接收reject的promise时会抛出异常 */
let promise = asyncFn();
promise
.then(() => {
requestCount -= 1;
if (taskQue.length) {
taskQue.shift()();
}
})
.catch(() => {
requestCount -= 1;
if (taskQue.length) {
taskQue.shift()();
}
});
return promise;
};
return executor;
}