JS实现异步请求的并发控制

389 阅读2分钟

常见要求

  1. 保证请求结果的顺序OR不需要保证请求结果的顺序 ×保证执行的顺序(串行才可以实现) √保证请求结果的顺序
  2. 发送多个请求,不管成功还是失败OR全都成功.没有回调函数
  3. 需要另外的函数触发,才执行.触发之后有新请求来了,要继续执行的 OR 没有触发
  4. 得到请求结果(不管成功还是失败)执行回调函数OR全都成功执行回调函数

代码(不保证顺序,不管成功/失败,不需要另外函数触发,请求结束后不管成功/失败执行回调)

//tasks 存储并发请求的数组,tasks[i]执行后,发送一个并发请求
//pool  最大并发数
//cb    需要执行的回调函数
function createRequest(tasks,pool,cb){
  //第一步:参数校验 三个都必须有 此处省略

  //TaskQueue管理请求
  class TaskQueue{
    constructor(pool,cb){
      this.running=0;   //执行中请求个数
      this.queue=[];    //存储需要执行的请求
      this.results=[];  //结果,成功/失败
      this.pool=pool;   //并发数
    }
    pushTask(task){     
      this.queue.push(task);  //全都存储在queue里面
      //执行next(),能不能真的执行,看next()里面判断.反正已经存到queue里面了
      this.next();            
    }
    
    next(){
      //this.running<this.pool 不能取"="
      //queue.length  任务队列里面还有任务
      //只有小于并发数并且队列里面有任务才会执行
      while(this.running<this.pool && queue.length){
        this.running++;
        let task=this.queue.shift();
        task().then(res=>{
          this.result.push(res);
        }).finally(()=>{
        //不管成功还是失败,正在执行并发数-1,执行下一个任务
          this.running--;
          this.next();
      })
      }   
      //都执行完了,执行回调函数
      if(this.running==0)  cb(this.results);  
    }
  }
  let TQ=new TaskQueue(pool,cb);
  tasks.forEach(task=>TQ.pushTask(task));
  //需要追加请求,调用TQ.pushTask()即可
  return TQ;
}

改进

保证顺序

新增index,保存执行的顺序

  function createRequest(tasks,pool,cb){
    class TaskQueue{
      constructor(){
        this.running=0; 
        this.queue=[]; 
        this.results=[];
        this.pool=pool;
        this.index=0;   //新增
      }
      pushTask(task){
        this.queue.push(task);
        this.next();
      }
      next(){
        while(this.running<this.pool &&queue.length){
          this.running++;
          let cur=this.index;   //新增
          let task=this.queue[this.index++];  //取的时候的记录一下顺序
          task().then(res=>{
            this.result[cur]=res;  //加到对于的结果里面
          })
          .finally(()=>{
            this.running--;
            self.next();
          })
        }  
        if(this.running==0) cb(this.results);
      }
    }
    let TQ=new TaskQueue;
    tasks.forEach(task=>TQ.pushTask(task))
  }

需要另外的函数触发

  function createRequest(tasks,pool,cb){
    let go=false;
    class TaskQueue{
      constructor(){
        this.running=0; 
        this.queue=[]; 
        this.results=[];
        this.pool=pool;
      }
      pushTask(task){
        this.queue.push(task);
        this.next();
      }
      next(){
        if(!go) return;
        while(this.running<this.pool &&queue.length){
          this.running++;
          let this.queue.shift();
          task().then(res=>{
            this.result.push(res);
            })
          .finally(()=>{
            this.running--;
            self.next();
          })
        }  
        if(this.running==0) cb(this.results);
      }
    }

    let TQ=new TaskQueue;
    tasks.forEach(task=>TQ.pushTask(task));
    
    //外部函数需要调用trigger才能触发
    createRequest.trigger=function(){
      go=true;
    }
  }