在前端的日常开发中,经常会碰到并发任务的处理。在有了promise后,处理并发任务变得简单。那如何优雅的处理并发任务呢?首先我们需要先分析一下并发任务的执行过程。
如上图,假设有10个待执行的任务,我们需要同时执行3个并发,nextIndex为任务下标。程序开始,任务1-3同时开始执行(调用任务函数),任务4-10等待执行。当任务1-3有任务执行完成,就可以继续执行等待中的任务。
当任务数大于并发数
假设10个任务,3个并发,任务的初始下标nextIndex=0
- 执行任务1,nextIndex=1
- 执行任务2,nextIndex=2
- 执行任务3,nextIndex=3
设任务1、2、3按顺序执行完成:
- 任务1优先完成,此时nextIndex=3(执行任务3的时候被设置为3),任务4进入执行阶段,nextIndex=4
- 任务2执行完成时,此时nextIndex在执行任务4的时候被更改为4,所以任务2执行完后,任务5进入执行阶段,nextIndex=5
- 任务3执行完成时,此时nextIndex在执行任务5的时候被更改为5,所以任务3执行完后,任务6进入执行阶段,nextIndex=6
当任务数小于并发数
当任务数小于并发数的时候,则我们只需要同时执行所有任务数即可
任务什么时候完成
我们定义一个finishCount,每完成一个任务时,我们需要将finishCount加1,当finishCount等于任务数时,则任务完成,返回最终结果
具体代码如下
/**
* 并发执行任务
* @param {Function[]} tasks
* @param {Number} paralleCount
* @returns {Promise<unknown>}
*/
function paralleTask(tasks, paralleCount = 2) {
return new Promise(resolve => {
//特殊情况
if (tasks.length === 0) {
resolve();
return;
}
let nextIndex = 0;//记录下一个任务的下标
let finishCount=0;//任务完成数
function _run() {
//运行下一个任务
const task = tasks[nextIndex];
nextIndex++;
task().then(() => {
finishCount+=1;
//还有下一个任务,运行下一个
if (nextIndex < tasks.length) {
_run();
}else if(finishCount===task.length){//所有任务完成时机
resolve()
}
})
}
// 并发执行任务,并判断任务数小于并发数
for (let i = 0; i < paralleCount && i < tasks.length; i++) {
_run();
}
})
}
const tasks = [];
paralleTask(tasks, 4).then(() => {
console.log('全部完成');
})