为何打印XMLHttpRequest请求响应时返回undefined?
为什么你的HttpRequest get方法总是返回undefined?
嘿,我来帮你把这个问题掰明白——核心原因其实是AJAX请求是异步执行的,这也是你用return拿不到结果的关键所在。咱们一步步拆解你的代码问题:
先看第一个版本的代码问题
你最开始的代码里,犯了两个关键错误:
- 你在
get方法最后直接return callback;,但这时候AJAX请求还在后台跑呢!因为open的第三个参数是true(异步模式),代码不会等待请求完成,会直接跳过请求流程执行return,这时候callback还是你传入的初始值(或者undefined),所以console.log自然输出undefined。 - 你在
onreadystatechange回调里写callback = httpRequest.responseText;是错的,应该是调用这个回调函数,把结果传进去,而不是给变量赋值。
再看第二个版本的代码问题
你修改后尝试在回调里return httpRequest.responseText;,但这个return只属于onreadystatechange这个内部函数,和外层的get方法没关系!外层的get方法在发送请求后就已经执行完毕了,根本等不到这个内部函数的返回值,所以get方法默认返回undefined,console.log还是拿不到结果。
为什么return不能替代callback?
这就得说清楚异步的本质:当你发送异步AJAX请求时,浏览器会把这个请求放到后台处理,同时继续执行后面的代码。等请求完成(拿到响应)后,才会触发onreadystatechange回调。这时候外层的get方法早就跑完了,你根本没法从get方法直接return还没生成的响应结果。
简单说:同步代码是按顺序一步步走,异步代码是“先去干活,干完了通知我”,你不能在“干活”的时候就想要结果。
正确的写法示例
方式1:正确使用回调函数
var HttpRequest = function() { this.get = function(url, callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function() { // 先判断请求是否完成 if(httpRequest.readyState == 4) { if(httpRequest.status == 200) { // 请求成功,调用回调把结果传进去 callback(null, httpRequest.responseText); } else { // 请求失败,也要把错误传给回调 callback(new Error(`请求失败,状态码:${httpRequest.status}`), null); } } }; httpRequest.open("GET", url, true); httpRequest.send(null); }; }; var request = new HttpRequest(); // 使用时传入回调函数处理结果 request.get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=BTC,USD", function(error, response) { if(error) { console.error(error); return; } console.log(response); // 这里才能拿到正确的响应内容 });
方式2:用Promise(更现代的写法)
现在大家更倾向于用Promise来处理异步操作,代码更清晰,还能避免回调地狱:
var HttpRequest = function() { this.get = function(url) { // 返回一个Promise对象 return new Promise(function(resolve, reject) { var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function() { if(httpRequest.readyState == 4) { if(httpRequest.status == 200) { // 请求成功,用resolve返回结果 resolve(httpRequest.responseText); } else { // 请求失败,用reject返回错误 reject(new Error(`请求失败,状态码:${httpRequest.status}`)); } } }; httpRequest.open("GET", url, true); httpRequest.send(null); }); }; }; var request = new HttpRequest(); // 用then处理成功,catch处理失败 request.get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=BTC,USD") .then(function(response) { console.log(response); }) .catch(function(error) { console.error(error); }); // 或者用async/await(需要在async函数中使用) async function fetchBTCPrice() { try { var response = await request.get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=BTC,USD"); console.log(response); } catch(error) { console.error(error); } } fetchBTCPrice();
内容的提问来源于stack exchange,提问作者Jordan Baron
相关产品推荐
相关产品推荐

