背景
在比较大型的项目中,可能需要一次性发送几十上百次的请求,如此规模的TCP连接建立,可能会阻塞其他的资源请求,需要控制请求的并发数量
,避免此问题。
分析
- 确认
最大并发数
- 使用
队列
的数据格式来缓存任务,因为任务执行顺序是先进先出的 - 定义一个运行函数,当最大并发数 < 当前运行数 && 任务队列不为空时,取出列表的第一项任务执行
- 提供一个添加任务的方法
实现
// 并发任务队列
class ParallelTaskList {
// 最大并发数
parallelCount = 0
// 总任务数
tasksCount = 0
// 任务队列
tasks = []
constructor(parallelCount = 2) {
this.parallelCount = parallelCount
}
// 添加任务
add(task) {
return new Promise((resolve, reject) => {
// 添加任务到队列中
this.tasks.push({
task,
resolve,
reject
})
// 运行任务
this._run()
})
}
// 批量添加任务
batchAdd(taskList) {
taskList.forEach((task) => this.add(task))
}
// 依次运行任务队列中的所有任务
_run() {
if (this.runningCount < this.parallelCount && this.tasks.length) {
// 正在运行的数量+1
this.runningCount++
// 队列先进先出原则,取出任务队列中的第一项任务
const { task, resolve, reject } = this.tasks.shift()
// 执行任务
task()
.then(resolve, reject)
.finally(() => {
// 执行完毕后,正在运行的数量-1
this.runningCount--
// 递归调用
this._run()
})
}
}
}
调用
function task1() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('任务1执行完毕')
resolve()
}, 1000)
})
}
function task2() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('任务2执行完毕')
resolve()
}, 4000)
})
}
function task3() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('任务3执行完毕')
resolve()
}, 4000)
})
}
// 实例化
const parallelTaskList = new ParallelTaskList()
parallelTaskList.add(task1) // 1秒后执行完毕
parallelTaskList.add(task2) // 4秒后执行完毕
parallelTaskList.add(task3) // 5秒后执行完毕(任务1执行后执行该任务,1+4=5)
// parallelTaskList.batchAdd([task1, task2, task3])