实现一个promise.all,并限制并发量

3,132 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

这道题也是我之前面试字节的一道题,写出来跟大家分享下。

模拟请求

因为是实例,没有真实的请求,我们利用promise和setTimeout来模拟请求的执行。

function delay(text,time){
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve(text)
        },time)
    })
}

有2个参数,一个text来区分不同的请求,一个time表示请求的时间。

Promise.all实现

function myPromiseAll(arr){
    return new Promise((resolve,reject) => {
        let count = 0 
        const n = arr.length 
        const res = new Array(n)
        for(let i = 0; i < n; i++){
            const p = arr[i]
            Promise.resolve(p()).then(result => {
                res[i] = result 
                count++ 
                if(count === n){
                    resolve(res)
                }
            })
        }
    })
}

const p1 = () => delay('1',1000)
const p2 = () => delay('2',1500)
const p3 = () => delay('3',500)

const p = [p1,p2,p3]

myPromiseAll(p).then(res => console.log(res))

实现一个普通的Promise.all很简单,关键在于要定义一个count变量,每执行完一个promise,count+1,在count等于输入数组的长度时,输出。

实现一个可以限制并发数的Primise.all

什么叫限制并发量?

限制并发量,比如说我们Promise.all(p1,p2,p3,p4,p5),限制并发量为3,每时每刻只能有3个请求,注意不是先执行完前3个请求之后,再执行后3个请求哦,是每时每刻都有3个请求执行。

const p1 = () => delay('1',5000)
const p2 = () => delay('2',2000)
const p3 = () => delay('3',3000)
const p4 = () => delay('4',2000)
const p5 = () => delay('5',3000)


const p = [p1,p2,p3,p4,p5]

我们看上面的例子, 先执行 p1 p2 p3 这三个请求,p2 最先执行完,然后执行p4, 然后是p3执行完,再执行p5

输出的结果是2,3,4,1,5; 而不是我们预想的先执行完前3个,再执行后两个

具体实现

function myPromiseAll(arr,limit){
    return new Promise((resolve,reject) => {
        let count = 0 
        const n = arr.length 
        const res = new Array(n)
        let index = 0
        function step(i){
            if(count === n) {
                resolve(res)
                return 
            }
            if(arr[index]){
                arr[index]().then(result => {
                    res[i] = result 
                    count++
                    step(index)
                }) 
            }
            index++
        }
        for(let i = 0; i < limit; i++){
            step(i)
        }
    })
}

const p1 = () => delay('1',5000)
const p2 = () => delay('2',2000)
const p3 = () => delay('3',3000)
const p4 = () => delay('4',2000)
const p5 = () => delay('5',3000)

const p = [p1,p2,p3,p4,p5]

myPromiseAll(p,3).then(res => console.log(res))

看下结果:

image.png

主要看一下几个参数,函数的参数i,来保证promise是按顺序存入res里面的。

index参数来保证promise的执行顺序。