在前端开发中,尤其是在处理网络请求或异步任务时,我们经常会遇到需要并发执行多个任务的场景。然而,过多的并发请求可能会导致服务器负载过高,甚至被拒绝服务。为了解决这个问题,我们可以使用并发控制技术来限制同时进行的任务数量,从而实现更加稳定和高效的异步操作。

本文介绍一个名为 concurTask 的函数,它可以帮助我们控制并发任务的执行,确保在任何时候不会超过设定的最大并发限制。

问题背景

在实际开发中,如果我们需要同时发起多个网络请求,直接并发所有请求可能会带来以下问题:

  1. 服务器压力过大:如果并发请求数量过多,服务器可能无法处理,导致请求失败。
  2. 资源竞争:浏览器对同一域名的并发请求有数量限制,过多的并发请求可能会阻塞其他重要资源的加载。
  3. 不必要的网络流量:如果所有请求都同时发起,即使有些请求的数据不立即需要,也会消耗网络资源。

为了解决上述问题,我们需要一种机制来控制并发请求的数量,在保证任务执行效率的同时,降低对系统的冲击。

concurTask 函数实现

concurTask 函数接收一个任务列表和一个并发限制参数,按顺序执行这些任务,确保同时执行的任务数量不超过设定的限制。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const concurTask = (tasks, limit = 1) => {
return new Promise((resolve) => {
const results = []
if(!tasks || !tasks.length) {
resolve(results)
return;
}

let currentIndx = 0;

const _run = async () => {
if(currentIndx >= tasks.length) return;
const i = currentIndx;
const task = tasks[currentIndx]
currentIndx++;
try {
const result = await task();
results[i] = result
} catch (error) {
results[i] = error
} finally {
if(results.length === tasks.length) {
resolve(results)
} else {
_run()
}
}
}

const count = Math.min(tasks.length, limit)
for(let i = 0; i< count; i++) {
_run()
}
})
}

使用示例

假设我们有一组模拟的异步 HTTP 请求任务,我们想要以每次最多两个任务的并发来执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 异步 HTTP 请求模拟函数
async function http(url) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(url); // 模拟请求的 URL
resolve(url);
}, 1000); // 模拟请求延迟 1 秒
});
}

// 使用 concurTask 控制并发请求
concurTask([
'http://127.0.0.1:3000/1',
'http://127.0.0.1:3000/2',
'http://127.0.0.1:3000/3'
].map(item => () => http(item)), 2);

在这个示例中,我们通过 concurTask 函数控制了同时执行的异步任务数量,确保每次最多只有两个任务在执行。这种方法能有效地管理资源,并降低了因并发过高导致的性能问题和竞态条件风险。

通过 concurTask 函数,开发者能够更加灵活地处理异步任务的执行顺序和并发限制,从而优化应用程序的性能和稳定性。