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