7. 控制并发请求
来源:百度二面
题目
实现一个并发控制器,限制同一时间最多只能有 n 个异步任务同时执行。
代码
js
// 控制并发请求
// 百度二面
// 模拟发送请求接收到数据:返回一个promise,time时间到了,promise完成
function timeout(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, time)
})
}
class SuperTask {
constructor(maxCount = 2) {
// 最大并发数量
this.maxCount = maxCount
// 请求队列
this.requestQueue = []
// 当前正在进行请求的并发数
this.currentCount = 0
}
// 添加任务到请求队列中
add(task) {
return new Promise((resolve, reject) => {
this.requestQueue.push({
task,
resolve,
reject
})
// 尝试执行任务
this.run()
})
}
// 执行任务:判断当前的并发数,执行我们的任务
run() {
while (this.currentCount < this.maxCount && this.requestQueue.length !== 0) {
// 拿出任务
const { task, resolve, reject } = this.requestQueue.shift()
this.currentCount++
// 执行任务,在执行完毕后,需要再次调用run
task().then(resolve, reject).finally(() => {
// 任务执行完毕
this.currentCount--
this.run()
})
}
}
}
const superTask = new SuperTask(2)
function addTask(time, name) {
superTask.add(() => timeout(time)).then(() => {
console.log(`任务${name}完成`)
})
}思路
使用队列 + 计数器实现一个简单的任务调度器。
- 用
requestQueue保存还没执行的任务 - 用
currentCount记录当前正在执行的任务数量 - 每次
add新任务后,都尝试调用run run在并发数未满时,从队列中取出任务执行- 任务结束后把
currentCount减一,再继续调度后面的任务
关键点
maxCount控制最大并发数requestQueue负责保证任务先进先出finally很关键,无论任务成功还是失败,都要释放并发占位- 每个任务执行完成后再次调用
run,可以持续拉起后续排队任务 - 时间复杂度取决于任务数量,调度部分整体是