- 面试题中,有一道题经常会出现,咱们下面讲一下思路以及写法
- 写一个方法,传入一个请求地址数组,以及一个并发数量,根据并发数量,一起发送请求。如果一个发送完,那么从数组中拿出来一个接着发送,最多一起发送三个,直到结束为止。并且这个方法最终返回的结果为前面多个请求结果组成的数组,且结果顺序和请求地址数组顺序一致。
1.编写方法基本框架
/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
const resList = await sendPostRequestInParallel(urls, 3);
console.log(resList);
2.内部方法,每次获取一条并发送
![test](C:/Users/tcc-computer/Pictures/test.gif)/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {
let index = 0; // 要处理的下一条 url 索引
const results = []; // 存放请求结果
async function _request() {
const url = urls[index];
// 用变量保存下当前索引
const i = index;
index++;
try {
// 发送请求,并且吧结果放入对应为止
const res = await fetch(url);
results[i] = await res.json();
} catch (err) {
// 失败的话,就把失败原因加进去,这里不能使用push,不然结果顺序和参数地址顺序不一致
results[i](err);
}
console.log(results);
}
// 这里现调用3次测试
_request();
_request();
_request();
});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
sendPostRequestInParallel(urls, 3);
我们把网速调慢,进行测试
3、递归处理
- 当一条处理完以后,要从数组中再拿出来一条执行,直到执行完最后一条
/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {
let index = 0; // 要处理的下一条 url 索引
const results = []; // 存放请求结果
async function _request() {
const url = urls[index];
// 用变量保存下当前索引
const i = index;
index++;
try {
// 发送请求,并且吧结果放入对应为止
const res = await fetch(url);
results[i] = await res.json();
} catch (err) {
// 失败的话,就把失败原因加进去,这里不能使用push,不然结果顺序和参数地址顺序不一致
results[i](err);
} finally {
// 如果一条执行完,则继续拿出来下一条执行,直到urls执行完
if (index < urls.length) {
_request();
}
}
console.log(results);
}
// 这里现调用3次测试
_request();
_request();
_request();
});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
sendPostRequestInParallel(urls, 3);
4、处理限制并发数
- 上面我们手动执行了三次,要改成循环 参数中的并发数
/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {
let index = 0; // 要处理的下一条 url 索引
const results = []; // 存放请求结果
async function _request() {
const url = urls[index];
// 用变量保存下当前索引
const i = index;
index++;
try {
// 发送请求,并且吧结果放入对应为止
const res = await fetch(url);
results[i] = await res.json();
} catch (err) {
// 失败的话,就把失败原因加进去,这里不能使用push,不然结果顺序和参数地址顺序不一致
results[i](err);
} finally {
// 如果一条执行完,则继续拿出来下一条执行,直到urls执行完
if (index < urls.length) {
_request();
}
}
console.log(results);
}
// 这里取 最小值,防止urls长度小于maxNum
for (let i = 0; i < Math.min(urls.length, maxNum); i++) {
_request();
}
});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
sendPostRequestInParallel(urls, 3);
5、处理函数返回值
- 接口请求有快有慢,最后一个接口请求完,有可能结果还没返回完,所以并不是返回值的时候,那么我们就要等所有的接口都请求完成才可以返回,这里定义一个变量
count
,每一个请求返回结果后再++,直到count==urls.length
/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {
let index = 0; // 要处理的下一条 url 索引
const results = []; // 存放请求结果
let count = 0; // 记录已经完成的请求个数
async function _request() {
const url = urls[index];
// 用变量保存下当前索引
const i = index;
index++;
try {
// 发送请求,并且吧结果放入对应为止
const res = await fetch(url);
results[i] = await res.json();
} catch (err) {
// 失败的话,就把失败原因加进去,这里不能使用push,不然结果顺序和参数地址顺序不一致
results[i](err);
} finally {
// 如果一条执行完,则继续拿出来下一条执行,直到urls执行完
if (index < urls.length) {
_request();
}
count++;
if (count === urls.length) {
resolve(results);
}
}
}
// 这里取 最小值,防止urls长度小于maxNum
for (let i = 0; i < Math.min(urls.length, maxNum); i++) {
_request();
}
});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
sendPostRequestInParallel(urls, 3).then((res) => {
console.log(res);
});
6、结束
- 至此,我们所有问题都已经解决了,下面是全部代码,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
/**
*
* @param {Array} urls 请求的url列表
* @param {Number} maxNum 最大并发数
* @returns
*/
function sendPostRequestInParallel(urls, maxNum) {
// 如果 urls 为空,直接返回一个空数组
if (urls.length === 0) {
return Promise.resolve([]);
}
// 结果为成功的,如果请求失败的话,把失败原因放数组中即可
return new Promise((resolve) => {
let index = 0; // 要处理的下一条 url 索引
const results = []; // 存放请求结果
let count = 0; // 记录已经完成的请求个数
async function _request() {
const url = urls[index];
// 用变量保存下当前索引
const i = index;
index++;
try {
// 发送请求,并且吧结果放入对应为止
const res = await fetch(url);
results[i] = await res.json();
} catch (err) {
// 失败的话,就把失败原因加进去,这里不能使用push,不然结果顺序和参数地址顺序不一致
results[i](err);
} finally {
// 如果一条执行完,则继续拿出来下一条执行,直到urls执行完
if (index < urls.length) {
_request();
}
count++;
if (count === urls.length) {
resolve(results);
}
}
}
// 这里取 最小值,防止urls长度小于maxNum
for (let i = 0; i < Math.min(urls.length, maxNum); i++) {
_request();
}
});
}
const urls = [];
for (let i = 1; i <= 10; i++) {
urls.push(`http://localhost:8888/testTcc?num=${i}`);
}
// 10个url,每次3个并发
sendPostRequestInParallel(urls, 3).then((res) => {
console.log(res);
});
</script>
</html>