题目:实现一个并发请求函数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