要求如下:
- 要求最大并发数 MAX
- 每当有一个请求返回,就留下一个空位,可以增加新的请求
- 所有请求完成后,结果按照 传入的任务 里面的顺序依次打出
思路: 任务队列 + max最大并发数 + 递归
我们将所有的请求放入到一个任务队列中。
每次从任务队列中拿取数量不超过 MAX 的任务并执行。
每拿出一个任务,MAX减1。
每执行完一个任务,MAX加1,将结果保留,并递归执行next函数,也就是执行任务队列中剩余的任务
同时,我们用一个count标识来统计已经执行完毕的任务数量,所有任务都执行完毕,则resolve结果队列
代码执行完毕
实现代码:
class TaskQueue {
constructor(max) {
this.max = max // 最大并发数
this.queue = [] // 任务队列
this.resultArr = [] // 结果队列
this.count = 0 // 任务数
}
/*
加入任务队列
*/
addTask(t) {
this.queue.push({
t, // 任务
index: this.count // 用来保存任务的顺序,保证结果是有序的
})
this.count++
}
/*
开始执行任务
*/
run() {
return new Promise(resolve => {
this.next(resolve)
})
}
/*
从任务队列中取出任务并执行
*/
next(resolve) {
let length = this.queue.length
if (length === 0) {
return
}
let min = Math.min(this.max, length) // 每次拿取的任务数不能超过max和队列长度,所以取最小值
for (let i = 0; i < min; i++) {
let {t,index} = this.queue.shift()
this.max--
t().then(result => {
console.log(result)
this.resultArr[index] = result //任务执行完毕,有序保留结果
})
.catch(error => {
console.log(error)
})
.finally(() => {
this.count-- // 任务数-1
if (this.count === 0) { // 所有任务都已经完成
resolve(this.resultArr)
}
this.max++ // 留出空位给下一个任务
this.next(resolve) // 执行下一次循环
})
}
}
}
测试
const task = (i) => {
return () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(i)
}, 2500);
})
}
}
async function test() {
const taskQueue = new TaskQueue()
for (let i = 0; i < 10; i++) {
taskQueue.addTask(task(i))
}
let p = await taskQueue.run()
console.log(p)
}
test()