You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript循环内使用fetch API的作用域问题及解决求助

解决循环中使用fetch API的作用域问题

嘿,我来帮你搞定这个问题!你遇到的这个提示是因为var声明的变量带来的作用域陷阱,加上fetch是异步操作,导致回调执行时拿到的不是你期望的迭代值。我来一步步给你解释并修改代码:

问题根源

你用var i来声明循环变量,var是函数级作用域,整个循环里只有一个i变量。当fetch的异步回调(then里的函数)执行时,循环早就跑完了,i的值已经变成了obj.length(也就是7),这时候obj[i]就是undefined,不仅会导致数据错误,还会触发那个lint警告——循环内的函数引用了外部作用域的共享变量。

另外,你的代码里push的是value:"ERROR",但预期输出里的键是status,这个也要修正哦。

方法1:用let代替var声明循环变量

let是块级作用域,每次循环迭代都会创建一个新的i变量,回调里拿到的就是当前迭代的那个i值,完美解决作用域问题:

const obj = [
  {"Id":"10101","descr":"server1.com"},
  {"Id":"10102","descr":"server2.com"},
  {"Id":"10103","descr":"server3.com"},
  {"Id":"10104","descr":"server4.com"},
  {"Id":"10105","descr":"server5.com"},
  {"Id":"10106","descr":"server6.com"}, 
  {"Id":"10107","descr":"server7.com"}
];

const temp = [];
// 把var改成let,让i变成块级作用域变量
for (let i = 0; i < obj.length; i++){      
  // 提前把当前项存下来,更稳妥
  const currentItem = obj[i];
  const id = currentItem.Id;      
  fetch(`https://abced.com/api/${id}/value`, {
    method : "GET",
    headers: { "Authorization": "xyz" }
  })
    .then(res => res.json())
    .then(data => { 
      const stats = data.status;          
      if (stats !== "OK") {
        // 修正键名为status,匹配预期输出
        temp.push({ Id: currentItem.Id, descr: currentItem.descr, status:"ERROR" });
      }
      console.log(temp);
    })
    .catch(x => console.log("fail:", x))
}

方法2:用forEach遍历数组

forEach的回调函数本身就有独立的作用域,每次迭代都会传入当前的数组项,完全避开作用域问题,代码也更简洁:

const obj = [
  {"Id":"10101","descr":"server1.com"},
  {"Id":"10102","descr":"server2.com"},
  {"Id":"10103","descr":"server3.com"},
  {"Id":"10104","descr":"server4.com"},
  {"Id":"10105","descr":"server5.com"},
  {"Id":"10106","descr":"server6.com"}, 
  {"Id":"10107","descr":"server7.com"}
];

const temp = [];
obj.forEach(currentItem => {
  const id = currentItem.Id;      
  fetch(`https://abced.com/api/${id}/value`, {
    method : "GET",
    headers: { "Authorization": "xyz" }
  })
    .then(res => res.json())
    .then(data => { 
      const stats = data.status;          
      if (stats !== "OK") {
        temp.push({ Id: currentItem.Id, descr: currentItem.descr, status:"ERROR" });
      }
      console.log(temp);
    })
    .catch(x => console.log("fail:", x))
});

方法3:用async/await + Promise.all(推荐)

如果希望所有请求完成后再统一得到结果(而不是每次回调都打印),用async/await结合Promise.all是更优雅的方式,还能保证结果的完整性:

const obj = [
  {"Id":"10101","descr":"server1.com"},
  {"Id":"10102","descr":"server2.com"},
  {"Id":"10103","descr":"server3.com"},
  {"Id":"10104","descr":"server4.com"},
  {"Id":"10105","descr":"server5.com"},
  {"Id":"10106","descr":"server6.com"}, 
  {"Id":"10107","descr":"server7.com"}
];

async function fetchAllServersStatus() {
  // 为每个服务器创建一个请求Promise
  const requestPromises = obj.map(currentItem => {
    const id = currentItem.Id;
    return fetch(`https://abced.com/api/${id}/value`, {
      method : "GET",
      headers: { "Authorization": "xyz" }
    })
    .then(res => res.json())
    .then(data => {
      // 只收集status不是OK的项
      if (data.status !== "OK") {
        return { Id: currentItem.Id, descr: currentItem.descr, status:"ERROR" };
      }
      return null; // status为OK的返回null,后续过滤掉
    })
    .catch(err => {
      console.log("请求失败:", err);
      // 请求失败也标记为ERROR
      return { Id: currentItem.Id, descr: currentItem.descr, status:"ERROR" };
    });
  });

  // 等待所有请求完成
  const allResults = await Promise.all(requestPromises);
  // 过滤掉null项,得到最终结果
  const temp = allResults.filter(item => item !== null);
  console.log(temp); // 这里就是你想要的预期输出!
}

// 调用函数
fetchAllServersStatus();

这个方法的好处是,你能确保所有请求都完成后再处理结果,而且代码逻辑更清晰,像同步代码一样易读。

内容的提问来源于stack exchange,提问作者user3046893

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 17:15:50