手写系列 | 如何限制并发数量

189 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

练习一些 JS 等手写的实现,是前端进阶的一种很好的方法,手写(或是手敲)可以帮助我们更好的了解实现原理,包括一些面试也经常会出现关于原理或是手写的题目。

那么,什么是限制并发数量呢?举个例子:去景区排队买票,一共有三个窗口,每当有人买完离开后,下一个人才能开始卖票,即一次最多三个人同时买票。如下图:

image.png

在代码中,当有很多个接口的时候,如果同时调用,可能会造成请求阻塞的问题,轻则页面卡顿,重则服务器崩溃 。所以为了避免这样的问题发生,优化性能,可以进行多请求的并发限制。

在这里,我们使用 setTimeout(...) 来模拟异步的代码

代码实现

思路:

  • 循环执行运行函数,循环的次数控制在最大并发数
  • shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值(shift()会改变数组的长度,这样就相当于执行一个移除一个,移除数组末尾的元素可以使用 pop() 方法)。
  • 待执行的数组中还存在函数,继续执行,当有一个执行完,继续执行下一个(递归
const promiseGenerator = (num) => {
    return new Array(num)
        .fill(0)
        .map((item, index) => () =>
            new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(index+1)
                    resolve(index)
                }, 1000)
            })
    )
}

const PromiseLimit = (allArr, limit) => {
    if(!Array.isArray(allArr)) throw new Error("不是数组类型")
    function run() {
        if(allArr.length) {
            allArr.shift()().then(res=>{
                allArr.length && run() 
            })
        }
    }
    for(let i=0;i<limit;i++) {
        run()
    }
}

const proArr = promiseGenerator(8)
PromiseLimit(proArr,5)

运行结果

当设定 1000 ms的执行时间时,可以看到前五个先执行,被控制并发的后面的几个再依次执行

动画.gif

注:一定要记得判断数组的长度和限制数量limit的大小关系,如果实际要执行的数组长度 < 限制的数量,不做判断会报错(TypeError: allArr.shift(...) is not a function