使用Fetch API的GET请求结合forEach循环无法批量获取API数据
解决React类组件中批量API请求导致的资源耗尽问题
我来帮你分析下问题所在,并用基础React类组件语法给出解决方案:
问题根源拆解
在
render中调用getPlants()是致命错误
React的render方法会在组件状态/ props变化、父组件渲染等多种场景下重复执行。你每次渲染都循环发起大量API请求,瞬间占用浏览器的网络资源,直接导致net::ERR_INSUFFICIENT_RESOURCES错误。未控制API请求并发量
直接用forEach一次性发起所有请求,会超出浏览器的并发连接限制(一般浏览器同时最多允许6-8个同域名请求),大量请求排队等待会耗尽系统资源。全局
datas变量不符合React状态管理逻辑
你直接用未初始化的全局数组存储结果,既无法触发组件重新渲染展示数据,也容易导致数据混乱。
基础React类组件解决方案
下面是修改后的完整代码,我会逐点说明关键改进:
class YourComponent extends React.Component { state = { items: [], plants: [] }; componentDidMount() { // 第一步:先获取组织数据 fetch('https://cors-anywhere.herokuapp.com/https://seffaflik.epias.com.tr/transparency/service/production/dpp-organization', { method: "GET", headers: { "Content-Type": "application/json", 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => response.json()) .then(resultJson => { this.setState( { items: resultJson.body.organizations }, // 关键:组织数据获取完成后,再调用getPlants,而不是在render里 this.getPlants ); }) .catch(err => console.error('获取组织数据失败:', err)); } getPlants = () => { const { items } = this.state; if (items.length === 0) return; // 1. 把每个请求包装成Promise const requestPromises = items.map(plant => { return fetch(`https://cors-anywhere.herokuapp.com/https://seffaflik.epias.com.tr/transparency/service/production/dpp-injection-unit-name?organizationEIC=${plant.organizationETSOCode}`, { method: 'GET', headers: { "Content-Type": "application/json", 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) throw new Error(`请求失败: ${response.status}`); return response.json(); }) .then(resultJson => resultJson.body.injectionUnitNames) .catch(err => { console.error(`获取plant ${plant.organizationETSOCode}数据失败:`, err); return []; // 出错时返回空数组,避免Promise.all失败 }); }); // 2. 用Promise.all批量处理请求,同时可以考虑分批优化(可选) Promise.all(requestPromises) .then(allPlantsData => { // 合并所有请求结果,更新组件状态 this.setState(prevState => ({ plants: [...prevState.plants, ...allPlantsData.flat()] })); }) .catch(err => console.error('批量获取plants数据失败:', err)); }; render() { const { plants } = this.state; return ( <div> {/* 在这里渲染plants数据,比如: */} {plants.length > 0 ? ( <ul> {plants.map((plant, index) => ( <li key={index}>{plant.name}</li> ))} </ul> ) : ( <p>加载中...</p> )} </div> ); } }
关键改进说明
- 把
getPlants移到componentDidMount的回调中:确保只有组织数据成功获取后,才发起后续请求,避免无效请求,也不会在render中重复触发。 - 用
Promise.all管理批量请求:既可以统一处理所有请求的结果,也能保证代码的可读性;如果请求数量特别多,可以进一步改成分批请求(比如每次只发5个请求,完成一批再发下一批)。 - 用组件状态
plants存储结果:替代全局datas,通过setState触发组件重新渲染,展示最新数据。 - 增加错误处理:每个请求都添加catch,避免单个请求失败导致整个批量请求崩溃,同时方便排查问题。
可选优化:限制并发请求数量
如果items的数量非常大(比如几十上百个),Promise.all一次性发起所有请求还是可能触发资源问题,这时候可以实现一个简单的并发限制函数:
// 工具函数:限制并发请求数量 const fetchWithConcurrency = (promises, limit) => { let index = 0; let results = []; let activeCount = 0; return new Promise((resolve) => { const next = () => { if (index >= promises.length && activeCount === 0) { resolve(results); return; } while (activeCount < limit && index < promises.length) { const promise = promises[index]; const currentIndex = index; activeCount++; index++; promise .then(res => { results[currentIndex] = res; }) .catch(err => { results[currentIndex] = []; console.error('请求失败:', err); }) .finally(() => { activeCount--; next(); }); } }; next(); }); }; // 在getPlants中使用: getPlants = () => { const { items } = this.state; if (items.length === 0) return; const requestPromises = items.map(plant => { // 这里和之前的请求Promise一样 return fetch(`https://cors-anywhere.herokuapp.com/https://seffaflik.epias.com.tr/transparency/service/production/dpp-injection-unit-name?organizationEIC=${plant.organizationETSOCode}`, { method: 'GET', headers: { "Content-Type": "application/json", 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) throw new Error(`请求失败: ${response.status}`); return response.json(); }) .then(resultJson => resultJson.body.injectionUnitNames) .catch(err => { console.error(`获取plant ${plant.organizationETSOCode}数据失败:`, err); return []; }); }); // 限制同时最多发起5个请求 fetchWithConcurrency(requestPromises, 5) .then(allPlantsData => { this.setState(prevState => ({ plants: [...prevState.plants, ...allPlantsData.flat()] })); }); };
这样就能进一步避免一次性占用过多网络资源,彻底解决net::ERR_INSUFFICIENT_RESOURCES错误。
内容的提问来源于stack exchange,提问作者alperenoz
相关产品推荐
相关产品推荐

