有10个异步请求,如何保持同时只有3个并发?

827 阅读2分钟

方式一:这里使用 Promise.race 来实现。
方式二:这里使用 删除请求时新增 来实现。

基本流程

方式一:

  • 创建一个大小为3的请求池
  • 立刻填充最多3个请求构造的promise
  • 立刻执行Promise.race
  • 删除已完成请求的promise,并加入一个新的
  • 重复Promise.race,直到完成所有请求

方式二:

  • 创建一个大小为3的请求池
  • 立刻填充最多3个请求构造的promise
  • promise中异步请求完成时,删除当前promise,加入一个新的promise到请求池中

发起的异步请求可以是promise数组吗?

不可以。 如果你传入了一个promise数组,这时所有的请求已经发出了。我们想要的是有10个请求准备发出(未发出)。

function query (timeout) {
    return new Promise(resolve => {
        setTimeout(() => resolve(x), x)
    })
}

// promise数组
const requestPmList = [100, 200, 300].map(x => query(x))

// 函数数组
const requestList = [100, 200, 300].map(x => () => query(x))

如何删除一个已完成的请求呢?

我们把异步请求函数封装成一个promise。
当Promise.race获取到最新请求结果时,在请求池中删除这个promise。

function createNewRequest (request) {
    const newRequest = request().then(res => {
        concurrentArr.splice(concurrentArr.indexOf(newRequest), 1)
        return res
    })
    return newRequest
}

完整代码

const timeoutArr = [1000, 3000, 2000, 9000, 8000, 7000, 5000, 3000, 1000, 700]
const requestArr = timeoutArr.map(timeout => () => query(timeout))
concurrentRequest2(requestArr, 3)

function query(timeout) {
    return new Promise(resolve => {
        setTimeout(() => resolve(timeout), timeout)
    })
}

// 方法一:使用Promise.race
function concurrentRequest(requestArr = [], concurrent = 3) {
    let i = concurrent
    const concurrentArr = requestArr.slice(0, concurrent).map(createNewRequest)
    run(concurrentArr)

    function createNewRequest(request) {
        const newRequest = request().then(res => {
            concurrentArr.splice(concurrentArr.indexOf(newRequest), 1)
            return res
        })
        return newRequest
    }

    function run(concurrentArr) {
        if (!concurrentArr.length) return
        Promise.race(concurrentArr).then(res => {
            console.log('弹出: ', res)
            if (i < requestArr.length) {
                concurrentArr.push(createNewRequest(requestArr[i++]))
            }
            run(concurrentArr)
        })
    }
}

// 方法二:删除请求时新增
function concurrentRequest2(requestArr = [], concurrent = 3) {
    let i = concurrent
    const concurrentArr = requestArr.slice(0, concurrent).map(createNewRequest)

    function createNewRequest(request) {
        const newRequest = request().then(res => {
            console.log('弹出: ', res)
            concurrentArr.splice(concurrentArr.indexOf(newRequest), 1)

            if (i < requestArr.length) {
                concurrentArr.push(createNewRequest(requestArr[i++]))
            }
            return res
        })
        return newRequest
    }
}

运行结果

example.gif

代码地址:有10个异步请求,如何保持同时3个并发?