笔者字节一面的时候遇到了下面这个面试题:
//支持并发的调度器, 最多允许2两任务进行处理
const scheduler = new Scheduler(2)
scheduler.addTask(1, '1’); // 1s后输出’1'
scheduler.addTask(2, '2’); // 2s后输出’2'
scheduler.addTask(1, '3’); // 2s后输出’3'
scheduler.addTask(1, '4’); // 3s后输出’4'
scheduler.start();
当时由于紧张和经验不够,一下子卡壳了,没能及时做出来(痛哭) 回来后好好想了一下,有了以下的思路:
- 首先用一个maxCount记录允许并发的数量,用一个tasks数组保存所有开始之前设定的任务
- 我们需要对加入的任务进行一些封装,改成promise,这样就可以获取到完成的状态进行操作
- 我们用working数组保存正在运行的任务,用tasks保存还未完成的任务
- 在任务完成后,将tasks队列的第一个任务放入working中,并且运行
- 如此,通过递归,就可以完成一个并发控制器
// 异步调度器
class Scheduler {
maxCount = 0
tasks = []
working = []
constructor(count) {
this.maxCount = count;
}
addTask = (timer, content) => {
// 控制函数
const target = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(content);
resolve();
}, 1000 * timer);
})
}
// 入队列
this.tasks.push(target)
}
continueWork = (fn) => {
// 递归终点(执行完成)
if (this.tasks.length > 0) {
// 将后面的拿进来继续执行
// 先确定下标
let idx = -1;
for (let i = 0; i < this.working.length; i++) {
if (fn === this.working[i]) {
// 将其替换并执行
idx = i;
break;
}
}
// 调用并运行
const next = this.tasks.shift();
next().then(() => {
this.continueWork(next)
})
this.working[idx] = next;
}
}
start = () => {
let len = this.tasks.length;
if (len >= this.maxCount) {
// 否则就将其加入工作队列并执行
this.working = this.tasks.splice(0, this.maxCount);
console.log(this.working.length)
this.working.map(fn => {
fn().then(() => {
// 完成后再回调
// 当前执行完毕
this.continueWork(fn);
})
})
} else {
//小于调度范围: 直接全部执行
this.tasks.map(fn => fn())
}
}
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!