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

为什么这段JavaScript的XMLHttpRequest回调代码会触发无限循环

问题原因
  • 全局复用同一个XMLHttpRequest实例:你在全局作用域只创建了一个XHR实例,每次调用moveiData函数都会给这个实例新增一个readystatechange事件监听器,旧的监听器不会被清除,每次XHR状态变化时所有绑定过的监听器都会依次触发
  • 成功分支未执行回调:你代码里仅在请求失败(readyState === 4但状态码不是200)时调用了回调函数,请求成功的逻辑分支是空的,没有把结果传递出去
  • 无限循环触发逻辑:第二次调用moveiData时,复用的全局XHR实例会触发第一次绑定的旧监听器,旧监听器触发后会再次执行回调里的moveiData调用,反复执行就形成了无限循环
修复方案

将XHR实例的创建移到moveiData函数内部,保证每次调用都生成独立的请求实例,同时补充成功分支的回调逻辑即可,修复后代码如下:

const url = new URL("https://www.breakingbadapi.com/api/quotes");

const moveiData = (link, callBack) => {
  // 每次调用都创建新的XHR实例,避免复用和重复绑定监听器
  const xhr = new XMLHttpRequest();
  xhr.addEventListener("readystatechange", () => {
    if (xhr.readyState === 4 && xhr.status == 200) {
      // 成功分支调用回调,返回解析后的接口数据
      callBack(null, JSON.parse(xhr.responseText));
    } else if (xhr.readyState === 4) {
      callBack("could not fetch data", null);
    }
  });

  xhr.open("GET", link);
  xhr.send();
};

moveiData(url, (err, response) => {
  if (err) return console.log(err);
  console.log('第一次请求结果:', response);

  moveiData(url, (err, response) => {
    if (err) return console.log(err);
    console.log('第二次请求结果:', response);
  });
});
补充说明

你现在练习的回调嵌套写法就是常说的「回调地狱」的原型,后续学习async-await就是为了优化这种嵌套逻辑,你现在的练习路径是合理的,理解底层回调逻辑后再封装Promise、使用async-await语法糖会理解得更透彻。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 02:45:02