JS 理解 Promise.race 控制并发量
废话开篇:比如在开发中会进行一系列的网络请求,但是有些情况需要控制一下网络请求请并发量。这里简单的用 Promise.race 及 await 的特性来理解一下,如何对任务的并发量进行控制。
一、Promise.race
Promise.race 作用就是将多个异步任务包裹起来,当有一个完成的话,那么就会触发 then 事件。除了这个不错的特性方法外,await 这个关键字也比较有用,可以这样理解,await 后面的代码其实就相当于在 Promise 的 then 事件,即:如果异步任务没有完成的话,await 后面的逻辑是不会执行的,可以联想一下 generator 生成器里面的 yield 它能直接控制方法体里面的代码执行跟暂停,外界由一个迭代器 next 方法进行操控。
await 虽然好用,也只是在一个“异步”方法里需要“同步执行”的时候。then 的异步回调,其实也有它的用处。可以将完全不关心的事务放到里面,由它去执行到最后的结果。
二、并发效果展示
这里有 6 个延迟异步任务,设置不同的并发量,输出一下结果
1、并发量为1
并发量为1的时候,一个任务的完成才会开启下一个任务
2、并发量为3
并发量为3的时候,开始就会有三个任务同时开始,当其中的某个任务完成后才会有新的任务加入进来。
三、代码
class ConcurrencyTask {
// 回调
callBack = ()=>{}
// 任务
task = ()=>{}
// 异步任务
promse = null
constructor(task,callBack){
this.task = task
this.callBack = callBack
}
// 开始进行任务
beginExecuteTask(){
this.promse = new Promise((resolve, reject)=>{
this.task(resolve,reject)
})
return this.promse
}
// 类方法初始化
static SimulationTask(time){
return new ConcurrencyTask((resolve, _)=>{
console.log('开始执行延时任务:' + (time / 1000) + '秒!')
setTimeout(()=>{
resolve('延时任务完成:' + (time / 1000) + '秒!')
},time)
},(res)=>{
console.log(res)
})
}
}
class ConcurrencyQueue {
// 最大并发数
maxConcurrencyNum = 1
// 并发任务集合
concurrencyTasks = []
// 正在进行的任务
executionTasks = []
constructor(maxConcurrencyNum,...concurrencyTasks){
this.maxConcurrencyNum = maxConcurrencyNum
concurrencyTasks.forEach((task)=>{
this.concurrencyTasks.push(task)
})
}
// 开始执行
async beginExecuteTasks(){
// 当前执行任务
this.executionTasks = []
// 全部任务
let allExecutionTasks = []
for(let index = 0;index < this.concurrencyTasks.length;index ++){
let task = this.concurrencyTasks[index]
// 开始并进行后续追踪
task.beginExecuteTask().then((res)=>{
this.executionTasks.splice(this.executionTasks.indexOf(task),1)
if(task.callBack){
task.callBack(res)
}
})
// 不足直接添加
if(this.executionTasks.length < this.maxConcurrencyNum){
//待执行任务集合添加
this.executionTasks.push(task)
//全任务执行集合添加
allExecutionTasks.push(task)
if((this.concurrencyTasks.length - 1) == index || this.executionTasks.length >= this.maxConcurrencyNum){
// 满足直接运行
await Promise.race(this.executionTasks.map((task)=>{ return task.promse }))
}
}
}
//全部任务完成
await Promise.all(allExecutionTasks.map((task)=>{ return task.promse }))
console.log('任务全部完成')
}
}
export { ConcurrencyTask ,ConcurrencyQueue }
ESM 模式导入,需要 node 简单起一个服务
<script type="module">
import { ConcurrencyTask ,ConcurrencyQueue } from "./concurrencyTask.js"
//添加任务
let concurrencyQueue = new ConcurrencyQueue(3,ConcurrencyTask.SimulationTask(1000),ConcurrencyTask.SimulationTask(6000),ConcurrencyTask.SimulationTask(5000),ConcurrencyTask.SimulationTask(4000),ConcurrencyTask.SimulationTask(2000),ConcurrencyTask.SimulationTask(3000))
//开始执行任务
concurrencyQueue.beginExecuteTasks()
</script>
四、总结与思考
如果知识点不能结合应用场景,那么,它其实没有什么需要记忆的必要性。但是如果简单的例子能给大家带来帮助,深感欣慰,代码拙劣,大神无笑[抱拳][抱拳][抱拳]
转载自:https://juejin.cn/post/7208858443630231612