并发任务等待控制
# 1. 应用背景
Promise 一般是用于异步处理当中,一般并发请求会采用 Promise.all ([]) 来进行请求,如果新增一些限制,比如:每次请求,最多请 求 2 个异步,当已完成之后,在 push 一个新的异步,此时 Promise.all 则无法实现。类似如下的函数:
存在一个 SuperTask 构造函数,通过调用 addTask 函数,入参传递一个 延迟时间
和 任务名称
,然后会在规定范围内,依次执行延迟函数,不过需要注意的是,依次只会同时请求 2 个,只有当其中一个执行完毕,才会请求另外一个。类似于在银行柜台排队办理业务,柜台有限,排队人数位置,当柜台空置才可以叫号
# 2. SuperTask 构造函数
class SuperTask {
constructor(parallelCount = 2){
this.parallelCount = parallelCount; // 最大并发数量
this.tasks = []; // 异步队列
this.runningCount = 0
this.add();
}
// 添加任务
add(task){
return new Promise((resolve,reject)=>{
this.tasks.push({
task,
resolve,
reject
}); // 添加到数组的时候, 同时保存当前的 成功失败函数, 供其他函数使用
this._run();
})
}
// 叫号函数
_run(){
// 当前在执行的任务数量 小于 最大并发数量 并且 异步队列有任务
while(this.runningCount < this.parallelCount && this.tasks.length){
const {task,resolve,reject} = this.tasks.shift(); // 从数组取出来第一个元素
this.runningCount ++; // 当前任务数量 + 1
// 因为不能确保task() 一定是一个异步函数, 因此需要用 promise.resolve 加工一下,确保是异步,可以调用 then 方法
Promise.resolve(task())
.then((resolve,reject)=>{
// 这里可以写 任务完成的函数 和 失败的处理函数
})
.finally(()=>{
this.runningCount --; // 任务完成, 即存在空位, 才可以继续叫号
this._run()
})
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 3. 函数校验
const superTask = new SuperTask();
function addTask(time,name){
superTask
.add(()=> timeout(time))
.then(()=>{
console.log(`任务${name}完成`)
})
}
addTask(1000*10,1) // 10s后输出任务1
addTask(5000,2) // 5s后输出任务2
addTask(3000,3) // 8s后输出任务3 存在等待了 5s
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
上次更新: 12/26/2023, 8:39:40 AM