题目:实现一个并发请求函数concurrencyRequest(urls, maxNum)
要求如下:
- 要求最大并发数 maxNum;
- 每当有一个请求返回,就留下一个空位,可以增加新的请求;
- 所有请求完成后,结果按照 urls 里面的顺序依次打出;
思路
首先是比较最大请求数量和总的urls的数量,如果urls数量更小,直接全部发送,然后返回结果;否则先发送最大的请求数量,发送一个将正在发送的数量减一,并追加一个新的请求,直到请求发送完毕,返回全部结果。
-
初始化结果数组和当前正在请求的数组: 我们需要一个数组来存储每个请求的结果,还需要一个数组来存储当前正在执行的请求。
-
编写一个异步函数来执行单个请求: 这个函数负责发送请求,并将结果存储到结果数组中。同时,它会从正在执行的请求数组中移除已完成的请求。
-
使用循环和 Promise实现并发请求: 我们使用循环来初始化一定数量的并发请求,并将它们加入到正在执行的请求数组中。
-
递归调用函数以填补新的请求: 在请求完成后,我们可以递归调用函数,从 URL 数组中取出新的请求,然后再次执行。
实现
async function concurrencyRequest(urls: string[], maxNum: number) {
return new Promise((resolve) => {
const results: any = [];
const executing: any = [];
const run = async (url: any) => {
try {
const response = await fetch(url);
results.push(response);
console.log("请求中", url);
} catch (error) {
results.push({ error: true, message: error.message });
} finally {
const index = executing.indexOf(url);
if (index !== -1) {
executing.splice(index, 1);
}
}
if (urls.length > 0 && executing.length < maxNum) {
const runUrl = urls.shift();
run(runUrl);
executing.push(runUrl);
}
if (urls.length === 0 && executing.length === 0) resolve(results);
};
// 初始化时,执行最多 maxNum 个请求
for (let i = 0; i < Math.min(maxNum, urls.length); i++) {
const url = urls.shift();
run(url);
executing.push(url);
}
});
}
// 使用
const urls = ["url1", "url2", "url3", 'url4','url5','url6', 'url7','url8'];
const maxNum = 3;
concurrencyRequest(urls, maxNum)
.then(results => {
console.log("结果", results);
})
.catch(error => {
console.error("发生错误:", error);
});
效果:
try/catch/finally
相信大家都会用try…catch吧, 这里简单介绍一下。在 JS中,try...catch
语句用于捕获异常,而 finally
语句块中的代码将在 try
块和任何 catch
块之后执行,无论是否发生异常。
无论是否发生异常,finally
块中的代码都会被执行。这意味着,无论 try
块中的代码是否成功执行,catch
块是否执行,finally
中的代码都将执行。
例如:
try {
// 一些可能抛出异常的代码
console.log("Try block");
throw new Error("An error occurred");
} catch (error) {
// 捕获异常的代码
console.error("Catch block:", error.message);
} finally {
// 无论是否发生异常,都会执行的代码
console.log("Finally block");
}
// 输出:
// Try block
// Catch block: An error occurred
// Finally block