如何仅用JavaScript通过XMLHttpRequest将多URL返回的JSON存入数组
问题根因拆解
你之前遇到的重复输出、数组填充失败的问题,都是对XMLHttpRequest的运行逻辑理解偏差、代码语法错误导致的,具体原因如下:
- 语法错误:
var jsonData[]不是合法的JS数组声明写法,等价于未正确初始化空数组 - 复用共享XHR对象导致重复触发:第一段代码所有请求共用同一个全局
XMLHttpRequest实例,反复调用open()时不会自动清除之前绑定的onreadystatechange回调,不同请求的状态切换会叠加触发回调,最终出现同一份数据重复输出两次的问题 - 数组赋值逻辑位置错误:第二段代码把
jsonData.push(data)写在成功判断分支外部,会在请求未完成、请求失败的场景下,把初始值data=0推入数组,根本无法存入真实的JSON响应 - 对XHR的回调触发逻辑理解偏差:
onreadystatechange不是只在请求成功完成时触发一次,而是会在请求的5个状态切换时反复触发;只有当readyState === XMLHttpRequest.DONE且status === 200时,才能拿到完整有效的响应内容 - 异步时序误判:XHR请求是异步执行的,
send()方法只是发起请求,不会阻塞等待响应返回;如果在发起请求的同步代码块中读取数组,此时回调还未运行,自然会觉得数组没有被填充。
可行实现方案
核心设计思路:每个请求使用独立的XHR实例,所有数组填充操作放在成功响应的分支内,通过完成计数器判断所有请求的返回状态,等全部拿到响应后再处理数组内容。
并发请求实现(请求数适中时优先选择,响应速度更快)
// 合法初始化空数组 const jsonData = []; // 记录已完成的请求数量,用于判断所有请求是否全部返回 let finishedCount = 0; // profiles为预先准备的、存储所有请求路径参数的数组 profiles.forEach((profileParam, index) => { const requestUrl = `https://url.com/profile=${profileParam}`; // 为每个请求创建独立的XHR实例,避免状态串扰 const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { // 仅当请求完全结束时处理逻辑 if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { // 解析JSON并存入数组对应位置 const resData = JSON.parse(xhr.responseText); jsonData[index] = resData; } else { // 可选:处理请求失败的场景 console.error(`请求失败,参数:${profileParam},状态码:${xhr.status}`); } // 已完成请求计数+1,直到和总请求数相等时说明全部完成 finishedCount++; if (finishedCount === profiles.length) { // 所有响应返回后,jsonData数组已完全填充,可在此处执行后续业务逻辑 console.log("所有请求完成,最终数据:", jsonData); } } } xhr.open("GET", requestUrl); xhr.send(); });
常见踩坑提醒
- 不要在
xhr.send()之后立刻读取jsonData数组:此时请求还在异步等待响应,数组为空是正常现象,必须在全部请求完成的回调中再使用数组数据 - 不要把数组填充、JSON解析的逻辑移出“请求成功”的判断分支,否则会推入无效的初始值
- 不要所有请求复用同一个XHR实例,很容易出现状态混乱、回调重复触发的问题
内容的提问来源于stack exchange,提问作者Sergikito
相关产品推荐
相关产品推荐

