循环内带setTimeout的Fetch请求仅返回最后一次迭代数据的问题
循环异步请求重复获取最后一次数据的问题解决
问题原因
- 循环里的
i用var声明,属于全局变量,setTimeout是异步任务,会在整个循环结束后才执行,此时i已经变成14,current_date也完成了最后一次更新,导致所有请求都用了最后一个日期的值。 - 移除
setTimeout后请求太密集,触发服务器限流机制(429错误),但此时部分请求能在current_date更新前执行,所以会看到非最后日期的数据。
解决方案
方案1:用let声明循环变量+复制日期+分散请求间隔
for(let i=0; i<14; i++){ // 更新 current_date const currentDateCopy = current_date; // 保存当前迭代的日期,避免后续更新覆盖 setTimeout(()=>{ const date_url = 'url_and_params' + currentDateCopy + 'rest_of_url'; fetch(date_url) .then(response => response.json()) .then(data=>{ console.log(data[0].stat1); data1.push(data[0].stat2); }) }, i * 1000) // 每次请求间隔1秒,避免429限流 }
let i让每个循环迭代拥有独立的块级作用域,确保setTimeout回调能捕获当前迭代的i值。- 复制
current_date到currentDateCopy,保证回调使用的是当前循环时的日期,而非最后一次更新的结果。 - 调整延迟为
i * 1000,让请求依次发送,避免触发服务器限流。
方案2:用闭包保存每次迭代的日期
for(var i=0; i<14; i++){ // 更新 current_date (function(currentIterationDate){ setTimeout(()=>{ const date_url = 'url_and_params' + currentIterationDate + 'rest_of_url'; fetch(date_url) .then(response => response.json()) .then(data=>{ console.log(data[0].stat1); data1.push(data[0].stat2); }) }, i * 1000); })(current_date); // 将当前日期传入闭包,固定值 }
- 用立即执行函数创建闭包,把当前迭代的
current_date作为参数传入,确保每个setTimeout回调拿到的是对应迭代的日期值。 - 同样通过
i * 1000分散请求间隔,避免429错误。
方案3:用async/await串行请求(更易维护)
async function fetchAllData() { for(let i=0; i<14; i++){ // 更新 current_date const date_url = 'url_and_params' + current_date + 'rest_of_url'; try { const response = await fetch(date_url); const data = await response.json(); console.log(data[0].stat1); data1.push(data[0].stat2); } catch (err) { console.error('请求出错:', err); } // 间隔1秒再发下一个请求 await new Promise(resolve => setTimeout(resolve, 1000)); } } fetchAllData();
- 用
async/await让请求按顺序执行,逻辑更直观,还能方便处理请求错误。 - 每次请求后等待1秒,彻底避免请求过于频繁导致的429错误。
内容的提问来源于stack exchange,提问作者beatmaister
相关产品推荐
相关产品推荐

