在前端开发中,并发请求是一个常见需求,尤其是在需要同时获取多个数据源的场景。合理地管理并发请求可以提升性能、优化用户体验,并降低服务器压力。以下是几种实现并发请求的方法及其控制策略。
使用 Promise.all 实现并发请求
Promise.all 是一种简单高效的方式,可以同时发送多个请求,并在所有请求完成后统一处理结果。
const fetchData1 = fetch('https://api.example.com/data1');
const fetchData2 = fetch('https://api.example.com/data2');
const fetchData3 = fetch('https://api.example.com/data3');
Promise.all([fetchData1, fetchData2, fetchData3])
.then(responses => Promise.all(responses.map(response => response.json())))
.then(data => console.log(data)) // 输出 [data1, data2, data3]
.catch(error => console.error('请求出错:', error));这种方法简单直观,但无法控制并发数量,适合请求数量较少的场景。
控制并发请求数量
在请求数量较多时,可以通过自定义函数限制并发数量。例如,以下代码实现了最大并发数控制:
const concurrencyRequest = (urls, maxNum) => {
return new Promise(resolve => {
if (urls.length === 0) {
resolve([]);
return;
}
const results = [];
let index = 0;
let count = 0;
const request = async () => {
if (index === urls.length) return;
const i = index;
const url = urls[index];
index++;
try {
const resp = await fetch(url);
results[i] = await resp.json();
} catch (err) {
results[i] = err;
} finally {
count++;
if (count === urls.length) resolve(results);
else request();
}
};
const times = Math.min(maxNum, urls.length);
for (let i = 0; i < times; i++) request();
});
};
// 测试
const urls = Array.from({ length: 20 }, (_, i) => `https://jsonplaceholder.typicode.com/todos/${i + 1}`);
concurrencyRequest(urls, 3).then(res => console.log(res));此方法通过限制同时运行的请求数量,避免了过多并发导致的性能问题。
使用并发控制库
可以借助第三方库(如 p-limit)实现更灵活的并发控制。
const pLimit = require('p-limit');
const limit = pLimit(3);
const fetchData = async () => {
const urls = ['https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3'];
const promises = urls.map(url => limit(() => fetch(url).then(res => res.json())));
const results = await Promise.all(promises);
console.log(results);
};
fetchData();这种方式适合复杂场景,能够精细控制并发数量。
错误处理与重试机制
在并发请求中,可能会出现部分请求失败的情况。可以通过 Promise.allSettled 或重试机制提高成功率。
const fetchWithRetry = async (url, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('请求失败');
return await response.json();
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(resolve => setTimeout(resolve, 1000 * 2 ** i)); // 指数退避
}
}
};注意事项
资源限制:合理设置并发数量,避免服务器过载或客户端性能下降。
错误处理:使用 Promise.allSettled 确保所有请求都被处理,无论成功与否。
安全性:确保请求通过安全渠道,并对敏感数据进行加密。
通过以上方法,可以根据实际需求灵活选择并发请求的实现方式,并结合错误处理和资源管理策略,提升前端性能和用户体验。