在javascript中,当同时需要执行多个任务或请求,但最大并发数有所限制时,可以利用该方案解决并发控制问题。
如题
// setTimeout模拟异步请求场景
function timeout(ms: number) {
return new Promise<void>(resolve => {
setTimeout(() => {
resolve();
}, ms);
})
}
const superTask = new SuperTask();
function addTask(time: number, name: number| string) {
superTask.add(() => timeout(time)).then(() => {
console.log(`${name}执行完毕`);
})
}
- 需要实现SuperTask类,确保代码执行结果如下
addTask(10000, 1); // 10ms后输出: 1执行完毕
addTask(5000, 2); // 5ms后输出: 2执行完毕
addTask(3000, 3); // 8ms后输出: 3执行完毕
addTask(4000, 4); // 12ms后输出: 4执行完毕
addTask(5000, 5); // 15ms后输出: 5执行完毕
分析
- 根据打印结果,可以判断出当前最大并发任务数是2个
SuperTas必须实现一个add方法,并且add方法返回的是一个promise
class SuperTask {
threadNum: number; // 最大线程数
runningNum: number; // 当前正在执行的任务数量
taskQueue: Array<any>; // 任务队列
constructor(threadNum = 2) {
this.threadNum = threadNum;
this.taskQueue = [];
this.runningNum = 0;
}
add(task: any) {
// 2.实现一个add方法并返回一个promise
return new Promise((resolve, reject) => {
// 将所有任务放进任务队列,然后按需取任务执行
this.taskQueue.push({
task,
resolve,
reject,
});
// 每当有任务进入队列时,都需要判断当前是否有空余线程可执行任务
this._run();
});
}
// 内部实现一个方法,当前执行任务小于可执行任务数时,从任务队列中取出任务执行
_run() {
while(this.runningNum < this.threadNum && this.taskQueue.length > 0) {
// 取第一个任务
const {task, resolve, reject} = this.taskQueue.shift();
this.runningNum++;
Promise.resolve(task()).then(resolve, reject).finally(() => {
this.runningNum--;
// 每当执行完一个任务,重新调用_run函数,执行下一个任务
this._run();
});
}
}
}
最终打印结果为
2执行完毕
3执行完毕
1执行完毕
4执行完毕
5执行完毕
完整代码示例
function timeout(ms: number) {
return new Promise<void>(resolve => {
setTimeout(() => {
resolve();
}, ms);
})
}
class SuperTask {
threadNum: number; // 最大线程数
runningNum: number; // 当前正在执行的任务数量
taskQueue: Array<any>; // 任务队列
constructor(threadNum = 2) {
this.threadNum = threadNum;
this.taskQueue = [];
this.runningNum = 0;
}
add(task: any) {
return new Promise((resolve, reject) => {
this.taskQueue.push({
task,
resolve,
reject,
});
this._run();
});
}
_run() {
while(this.runningNum < this.threadNum && this.taskQueue.length > 0) {
// 取第一个任务
const {task, resolve, reject} = this.taskQueue.shift();
this.runningNum++;
Promise.resolve(task()).then(resolve, reject).finally(() => {
this.runningNum--;
this._run();
});
}
}
}
const superTask = new SuperTask();
function addTask(time: number, name: number| string) {
superTask.add(() => timeout(time)).then(() => {
console.log(`${name}执行完毕`);
})
}
addTask(10000, 1); // 10ms后输出: 1执行完毕
addTask(5000, 2); // 5ms后输出: 2执行完毕
addTask(3000, 3); // 8ms后输出: 3执行完毕
addTask(4000, 4); // 12ms后输出: 4执行完毕
addTask(5000, 5); // 15ms后输出: 5执行完毕