为什么这段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
相关产品推荐
相关产品推荐

