实现一个具有并发数量限制的异步任务调度器,可以规定最大同时运行的任务。
方案1、任务队列,自调用,依次执行
useEffect(() => {
class Scheduler {
constructor (max) {
this.max = max; //? 最大执行量
this.curNum = 0; //? 当前执行的任务数量
this.taskQueue = []; //? 还未执行的所有任务队列
}
async add(asyncFun) {
if (asyncFun) this.taskQueue.push(asyncFun);
//* 当前执行的任务量大于等于最大执行量时,阻断
if (this.curNum >= this.max) return;
//* 当前执行的任务量小于最大执行量时,执行任务队列中的第一个任务
try {
this.curNum++;
const result = await this.taskQueue.shift()();
return result;
} catch(error) {
} finally {
this.curNum--;
this.taskQueue.length && this.add(); //* 当任务队列还有数据时,自调用执行
}
}
}
const scheduler = new Scheduler(2);
// 模拟成功的异步任务,接受一个id作为参数,返回一个延迟1秒后resolve的promise对象,值为id * 2
const successTask = (id) => () => new Promise((resolve) => { setTimeout(() => resolve(id), 2000) });
// 模拟失败的异步任务,接受一个id作为参数,返回一个延迟1秒后reject的promise对象,值为id * -1
const failTask = (id) => () => new Promise((_, reject) => { setTimeout(() => reject(id * -1), 3000)})
scheduler.add(successTask(1));
scheduler.add(failTask(2));
scheduler.add(successTask(3));
scheduler.add(failTask(4));
scheduler.add(successTask(5));
}, [])
方案2、使用await等待上一个任务执行完毕后,依次执行
useEffect(() => {
class Scheduler {
constructor (max) {
this.max = max; //? 最大执行量
this.curNum = 0; //? 当前正在执行的任务数量
this.queue = []; //? 等待队列
}
async add (asyncFun) {
//* 当前执行的任务量大于最大执行量时。需要等待正在执行的任务
if (this.curNum >= this.max) await new Promise(resolve => this.queue.push(resolve));
//* 当前执行的任务量小于等于最大执行量时,直接执行
try {
this.curNum++;
const result = await asyncFun();
return result;
} catch (error) {
} finally {
this.curNum--;
this.queue.length && this.queue.shift()(); //* 有正在等待的任务时,将等待队列中的第一个任务抽出来,使其等待结束,继续执行
}
}
}
const scheduler = new Scheduler(2);
// 模拟成功的异步任务,接受一个id作为参数,返回一个延迟1秒后resolve的promise对象,值为id * 2
const successTask = (id) => () => new Promise((resolve) => { setTimeout(() => resolve(id), 2000) });
// 模拟失败的异步任务,接受一个id作为参数,返回一个延迟1秒后reject的promise对象,值为id * -1
const failTask = (id) => () => new Promise((_, reject) => { setTimeout(() => reject(id * -1), 3000)})
scheduler.add(successTask(1));
scheduler.add(failTask(2));
scheduler.add(successTask(3));
scheduler.add(failTask(4));
scheduler.add(successTask(5));
}, [])