跳到主要内容

1 篇博文 含有标签「concurrent request」

查看所有标签

· 阅读需 5 分钟

完成一个并发请求的函数 concurRequest,它允许同时发送多个请求,但限制最大并发请求数

当全部请求全部收到响应结果后,返回一个数组,记录响应数据,同时保证响应顺序与参数的顺序一致

返回的 Promise 没有 reject 状态,只有 resolve,如果失败了只需提供失败原因即可

具体的实现思路如下:

  1. concurRequest 函数接受两个参数 urlsmaxNum,分别是待请求的 URL 数组和最大并发请求数。如果传入的 URL 数组为空,函数会直接返回一个解决(resolved)状态的 Promise 对象。
  2. concurRequest 函数中,定义异步函数 _request,用于发起单个请求,并将结果存储在 result 数组中。
  3. 初始化一些变量:index 表示下一次要请求的 URL 下标,result 数组用于存储所有请求的结果,doneCount 表示已经完成的请求数量。
  4. _request 函数中,我们先缓存下标 i 和当前请求的 URL url,然后通过 await 关键字发送请求并将结果存储在 result 数组中对应的位置。
  5. 无论请求是成功还是失败,我们需要增加 doneCount 的值,并在 finally 代码块中进行判断。如果所有请求都已完成,则使用 resolve 方法解析 Promise,并将 result 数组作为解决值。如果还有未完成的请求,继续调用 _request 函数以发送下一个请求。
  6. 最后,在 concurRequest 函数中,我们使用一个 for 循环来调用 _request 函数,最多同时执行 maxNum 个请求。

通过维护一个请求队列和计数器的方式,实现了并发请求的控制,保证最多同时发送指定数量的请求,并在所有请求完成后返回结果。这种实现方式可以在需要同时发起多个请求但又需要控制最大并发数的场景下使用。

const getUrls = (number = 10) => {
const result = []
for (let i = 1; i <= number; i++) {
result.push(`https://jsonplaceholder.typicode.com/todos/${i}`)
}
return result
}

/**
* 并发请求
* @param {string[]} urls 待请求的 url 数组
* @param {number} maxNum 最大并发数
*/
function concurRequest(urls, maxNum) {
if (urls.length === 0) {
return Promise.resolve([])
}
return new Promise((resolve) => {
let index = 0
const result = []
let doneCount = 0
async function _request() {
const i = index // 将 index 缓存到当前作用域下
const url = urls[index]
index++
try {
const res = await fetch(url)
result[i] = res
} catch (error) {
result[i] = error
} finally {
doneCount++
if (doneCount === urls.length) {
resolve(result)
}
if (index < urls.length)
_request()
}
}
for (let i = 0; i < Math.min(maxNum, urls.length); i++){
_request()
}
})
}

concurRequest(getUrls(10), 3).then(res => {
console.log(res)
})

Promise.all 以及 Promise.allSettled 区别

  1. 最大并发数的限制:concurRequest 函数一开始就限制了最大的并行请求数量 maxNum 。而 Promise.allPromise.allSettled 并不具有这样的限制,它们会立即启动所有传入的 Promise 。
  2. 错误处理:Promise.all 对 Promise 的错误处理是有敏感性的;如果 Promise 数组中任意一个 Promise 失败(rejected),整个 Promise.all 就会立刻失败,并且失败的原因是第一个失败的 Promise 的结果。而 Promise.allSettledconcurRequest 不会因为单个 Promise 失败而导致整体失败,它们会等待所有传入的 Promise 都结束,无论其结果是解决(resolved)还是失败(rejected)。
  3. 结果的返回:concurRequest 函数返回的是一个和输入一致的数组,结果的顺序保证和输入的 Promise 的顺序一致,它们的索引一一对应。而 Promise.allPromise.allSettled 则按照 Promise 完成的顺序确定结果的顺序。