面试官:设计一个异步并发限制吧

3,316 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

引言

异步问题是一个十分热门的问题,同时异步的处理也是十分复杂的问题。无论在前端还是后端,我们都绕不开异步这座大山。因此对异步的熟练掌握和灵活运用可以让我们的开发水平和理解能力如步青云。这一节我们简单的设计一个异步并发限制吧。

问题拆解

异步并发数限制问题还是比较容易理解,假设我们某个页面有10个接口数据需要请求,现在考虑到网络并发通道阻塞问题,现在需要限制这10个接口请求时最多一次性3个在处理,当最大请求次数超过3个时,未处理的接口只能等待。当有接口数据请求完成后,立即将请求资源给其余接口使用。这个处理是不是很像操作系统的线程任务队列。

综合上面的简单例子,我们可以知道这个异步并发限制的工具

  1. 队列,存储所有任务
  2. limit,保存当前最大异步请求接口的数量。

代码设计

//模拟接口请求
function getData(src) {
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      resolve(src)
    }, 1000);
  })
}

/*异步并发限制*/
function limitRequest(limit) {
  this.que = []
  this.limit = limit
  this.count = 0
  //添加任务
  this.push = function(task) {
    this.que.push(task)
    this.run()
  }
  //执行任务
  this.run = function() {
    //1.如果队列非空,并且当前正在运行个数<limit
    if(this.que.length && this.count<this.limit) {
      let task = this.que.shift()
      this.count++
      task.fn(task.src).then(msg=>{
        console.log(msg)
        this.count--
        this.run()
      })
    }
  }
}


//测试使用
let p = new limitRequest(2)//一次性最多执行2个任务
p.push({fn:getData,src:1})
p.push({fn:getData,src:1})
p.push({fn:getData,src:1})
p.push({fn:getData,src:1})

核心讲解

根据上面的功能拆解,其实问题已经十分清晰,我将简单列举下核心功能

  1. que模拟队列,保存所有任务
  2. limit表示一次性最多执行的接口数目
  3. count表示当前一次性正在执行任务的数目
  4. 设计添加任务push的方法,直接将任务添加队列,并尝试请求该接口
  5. 接口任务核心执行run方法,从任务队列取出队头任务执行,并将当前执行任务的数目+1,当任务执行完成后,当前执行任务数目-1。并继续调用run方法让其它资源执行。

执行效果

我们可以清楚的看到一次性最多请求2个接口的效果。

3.gif

总结

以上是我的个人小小设计和理解,希望大家在此基础上继续拓展和应用。如有疑惑,评论区见。