无法将XHR请求响应存入JavaScript变量的原因及解决
问题原因与解决方法
这问题我太熟悉了!核心原因是异步请求的执行时机没搞对,咱们一步步拆解:
为什么直接赋值会得到null?
你写的XHR请求是异步模式(open方法第三个参数是true),调用req.send()之后,浏览器会在后台发送请求,主线程不会等待请求完成,而是继续往下执行代码。这时候你立刻执行var myJSON = req.response;,请求还在进行中,readyState还没到4(请求完成的状态),response自然还是null。
那为什么后来在控制台重新赋值能拿到数据?很简单:等你在控制台输入代码的时候,后台的请求已经完成了,readyState变成4、status是200,浏览器已经把响应数据填充到req.response里了,这时候赋值当然能拿到正确的JSON对象。
解决方法:监听请求完成事件
异步请求的正确姿势是等请求完成后再处理响应数据,我们可以通过监听load事件来实现:
方法1:使用onload回调函数
var req = new XMLHttpRequest(); req.open('get', 'https://jsonplaceholder.typicode.com/todos', true); req.responseType = 'json'; // 当请求完成时触发这个回调 req.onload = function() { // 先判断请求是否成功 if (this.status === 200 && this.readyState === 4) { var myJSON = this.response; console.log(myJSON); // 这里就能拿到正确的JSON数据了 } else { console.error('请求失败:', this.status); } }; req.send();
方法2:使用addEventListener监听load事件
和上面的逻辑一致,只是写法更灵活(可以绑定多个事件处理函数):
var req = new XMLHttpRequest(); req.open('get', 'https://jsonplaceholder.typicode.com/todos', true); req.responseType = 'json'; req.addEventListener('load', function() { if (this.status === 200) { var myJSON = this.response; console.log(myJSON); } }); req.send();
额外推荐:改用fetch API(更现代的写法)
如果你不需要兼容特别老的浏览器,更推荐用fetch,它基于Promise,写法更简洁易读:
fetch('https://jsonplaceholder.typicode.com/todos') .then(response => { if (!response.ok) { throw new Error('请求失败'); } return response.json(); }) .then(myJSON => { console.log(myJSON); }) .catch(error => { console.error(error); });
内容的提问来源于stack exchange,提问作者Filip Hrnjez
相关产品推荐
相关产品推荐

