前言
前几天面试遇到的一道面试题,请手动实现一个并发请求函数,并获得每次请求得到的结果,因此这里记录一下。
一、并发请求
题目要求:有两个参数,分别是需要发送请求的url数组urls以及最大并发请求数maxNum,要求根据传入的参数maxNum实现最大并发请求并且以数组的形式返回所有的请求结果。
代码如下:
/**
* 并发请求
* @param {sting[]} urls 并发请求的url
* @param {number} maxNum 最大并发数
*/
function concurRequest(urls, maxNum) {
return new Promise((resolve) => {
// 特殊情况,urls里没东西
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 fetch(url)
// 将结果保存到数组中
results[i] = resp
} catch (error) {
// error加入到results中
results[i] = error
} finally {
count++
// 判断是否所有请求都已完成
if (count === urls.length) {
resolve(results)
}
request()
}
}
// 最大并发数和数组长度取最小值作为循环数
const times = Math.min(urls.length, maxNum)
for (let n = 0; n < times; n++){
request()
}
})
}
思路:
首先,因为是发生请求的函数,因此一定会异步调用,因为返回一个promise,
之后先进行特殊情况判断,如果传入的urls数组是空的,那么直接返回空数组即可。之后定义几个参数,分别是用于收集所有请求的返回结果(无论是成功还是失败)的数组results,下一个请求的数组下标index和当前请求完成的数量count。
然后定义一个发送请求的函数request,遍历urls数组,考虑到传入的最大并发数和urls数组长度的比较大小无法确定,因此取二者之间的最小值times进行遍历,之后循环调用request函数并传入当前请求的url,定义一个数组results用于收集所有请求的返回结果(无论是成功还是失败),当所有请求都完成时,通过调用promise的resolve方法将所有请求的结果数组results返回。
最后验证一下
const urls = []
for (let i = 1; i < 10; i++) {
urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`)
}
concurRequest(urls, 3).then((response) => {
console.log(response);
})
结果没有问题。
总结
本篇文章实现了一个简易的并发请求方案。