前言
遇到一个面试题,挺有意思的,关于异步队列并发控制的,直接看会有点绕,我会分析一下这里面的行为,我相信用其他方式也可以实现。
先上代码
/**
* 编写一个异步任务调度器
*/
class Scheduler {
list = []; //用来承载还未执行的异步
count = 0; //用来计数
constructor(num) {
this.num = num; //允许同时运行的异步函数的最大个数
}
async add(fn) {
// 锁
if (this.count >= this.num) {
await new Promise((resolve) => {
this.list.push(resolve);
});
}
this.count++;
console.log('fn before executed');
const result = await fn();
console.log('fn executed');
this.count--;
console.log('%c this.list.length %s', 'color: #bfffc8', this.list.length);
// 如果有任务完成 则后面排队接上
if (this.list.length > 0) {
console.log('this.list.shift()();');
this.list.shift()();
}
return result;
}
}
const schedule = new Scheduler(3); //最多同一时间让它执行3个异步函数
const asyncFactory = (n, time) => {
return () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(n);
}, time);
});
};
};
schedule.add(asyncFactory(1, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
schedule.add(asyncFactory(2, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
schedule.add(asyncFactory(3, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
schedule.add(asyncFactory(4, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
schedule.add(asyncFactory(5, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
schedule.add(asyncFactory(6, 2000)).then((n) => {
console.log(`异步任务:${n}`);
});
原理
我们知道可以同时进行n个任务
首先,将前n个任务异步执行
任务排序大于n的新任务(阻断resolve任务)推到一个队列数组里(这个resolve在没有执行之前会阻断后面代码的执行)
一开始同时执行n个任务,当其中任何一个任务结束之后,就会判断等待队列里是否有任务,如果有任务,就会把等待队列里的第一个任务(阻断resolve任务)拿出来,继续执行
当resolve阻断被fulfilled后,就会执行后面的异步任务