前端基础:并发请求

215 阅读2分钟

还是老样子先说说需求,如果有100个请求,如何使用Promise控制数量为为n最大并发

主要思路

image.png

以这张图为例,此时的最大并发数量为3,我们 从urls中取出三个url,依次发送请求,无论请求的结果是成功或者失败,依次按照顺序放入results中,当完成一个请求,从urls中取出下一个url地址,直至全部取出

function concurRequest(urls, maxNum) {
    return new Promise((resolve) => {
        if (urls.length === 0) {
            resolve([])
            return
        }
        const results = []
        function request() {}
    })
}

完成过程

1、我们使用index规定为下次发送url的下标

2、将请求成功/失败结果按照顺序放入resluts中,i用来记录每次的位置

3、当一个请求完成,发送下一个请求

tip:这里连续三次使用request来模拟并发数量为3,后续解决maxNum的问题

const results = []
let index = 0 //下一个请求的下标
async function request() {
    const i = index
    const url = urls[index]
    index++
    try {
        const resp = await axios(url)
        //resp加入results
        results[i] = resp
    } catch (err) {
        //err加入results
        results[i] = err
    } finally {
        request()
    }
}
request()
request()
request()

4、此时会遇到一个问题,在发送完所有请求后,urls会出现越界问题,这里需要限制一下 5、判断是否已经全部请求完成,设置count,在finally中说明已经完成一个请求,比较count和数组长度

async function request() {
    if (index === urls.length) {
        return
    }
    const i = index
    const url = urls[index]
    index++
    try {
        const resp = await fetch(url)
        results[i] = resp
    } catch (err) {
        results[i] = err
    } finally {
        count++
        if (count === urls.length) {
            console.log('over')
            resolve(results)
        }
        request()
        request()
        request()
    }
}

6、最后处理一下maxNum最大并发数量的问题,最大并发数量为n,我们就需要发送n个request,这里直接套一个循环即可

7、当urls的长度小于maxNum,这里我们需要取最小值

const times = Math.min(maxNum, urls.length)
for (let i = 0; i < times; i++) {
    request()
}

完整代码

/**
 * 并发请求
 * @param{string[]} 待urls请求的 url数组
 * @param{number} maxNum最大并发数
 */
function concurRequest(urls, maxNum) {
    return new Promise((resolve) => {
        if (urls.length === 0) {
            resolve([])
            return
        }
        const results = []
        let index = 0 //下一个请求的下标
        let count = 0 //当前请求完成的数量
        async function request() {
            if (index === urls.length) {
                return
            }
            const i = index
            const url = urls[index]
            index++
            try {
                const resp = await axios(url)
                results[i] = resp
            } catch (err) {
                results[i] = err
            } finally {
                count++
                if (count === urls.length) {
                    console.log('over')
                    resolve(results)
                }
                request()
            }
        }
        const times = Math.min(maxNum, urls.length)
        for (let i = 0; i < times; i++) {
            request()
        }
    })
}