调用getjson()控制台返回undefined,无法在onload外访问JSON数据
解决JSON数据异步获取后无法访问的问题
嘿,作为JS新手碰到这个问题太正常啦!咱们先搞清楚问题出在哪:你用的XMLHttpRequest是异步操作——也就是说,当你调用getjsonData的时候,请求还在后台跑呢,根本没等到数据返回就直接结束了,所以控制台才会返回undefined,而且onload函数外面也拿不到数据。
问题根源拆解
异步操作不会阻塞代码执行顺序:你调用retrieveJsonData后,代码会立刻继续往下走,不会等请求完成。只有当请求成功拿到数据后,onload里的代码才会执行。所以你想直接同步获取数据是行不通的,得用异步的方式来处理结果。
解决方案1:用回调函数处理异步结果
咱们可以给函数加个回调参数,等请求完成后把数据传给回调函数:
var DataController = (function(){ // 私有函数:接受回调函数作为参数 var retrieveJsonData = function(callback){ var api = 'http://52.69.49.40/assignment/getServiceData.php'; var ourRequest = new XMLHttpRequest(); ourRequest.open('GET', api); ourRequest.onload = function(){ // 记得用let/const声明变量,避免全局污染 const obj = JSON.parse(ourRequest.responseText); // 请求完成后调用回调,把数据传出去 callback(obj); }; // 别忘了发送请求! ourRequest.send(); }; // 公开方法:同样接受回调 return { getjsonData: function(callback){ retrieveJsonData(callback); } }; })(); // 调用的时候这样用: DataController.getjsonData(function(data){ console.log(data); // 这里就能拿到JSON数据啦 // 后续处理数据的逻辑都写在这里 });
解决方案2:用Promise(更现代的写法)
如果想让代码更清晰,也可以用Promise来封装异步请求,后续还能结合async/await使用:
var DataController = (function(){ var retrieveJsonData = function(){ return new Promise(function(resolve, reject){ var api = 'http://52.69.49.40/assignment/getServiceData.php'; var ourRequest = new XMLHttpRequest(); ourRequest.open('GET', api); ourRequest.onload = function(){ if(ourRequest.status >= 200 && ourRequest.status < 300){ const obj = JSON.parse(ourRequest.responseText); resolve(obj); // 请求成功,返回数据 } else { reject('请求出错啦:' + ourRequest.statusText); // 请求失败,返回错误 } }; ourRequest.onerror = function(){ reject('网络请求失败'); }; ourRequest.send(); }); }; return { getjsonData: function(){ return retrieveJsonData(); } }; })(); // 调用方式1:用.then() DataController.getjsonData() .then(function(data){ console.log(data); // 处理数据 }) .catch(function(error){ console.error(error); }); // 调用方式2:用async/await(需要在async函数里) async function fetchData(){ try { const data = await DataController.getjsonData(); console.log(data); } catch(error){ console.error(error); } } fetchData();
额外提醒
- 原代码里的
obj没有用var/let/const声明,会变成全局变量,这是不好的习惯,记得加上变量声明。 - 别忘了调用
ourRequest.send(),不然请求根本发不出去!
内容的提问来源于stack exchange,提问作者junaid
相关产品推荐
相关产品推荐

