JavaScript中创建Booking对象实例的异步请求返回问题
你的问题核心是没搞明白JavaScript里异步操作的执行逻辑——XMLHttpRequest是异步的,getBooking函数在调用request.send()后就直接结束了,返回undefined,而你在onload回调里的return根本传不到函数外面,所以const booking = getBooking('1')拿到的是undefined,自然访问booking.id会报错。
不用全局变量的话,有两种常用的解决方式:
方法一:用Promise封装异步请求(推荐,更符合现代JS写法)
把getBooking改成返回一个Promise,这样就能通过async/await或者.then()来获取异步返回的Booking实例:
// 优化Booking构造函数,直接传data对象更简洁 function Booking(data) { this.id = data.id; this.retailer_id = data.retailer_id; this.app_date = data.app_date; } function getBooking(booking_id) { return new Promise((resolve, reject) => { let request = new XMLHttpRequest(); let url = prefix.toString() + 'bookings/' + booking_id; request.open('GET', url, true); request.onload = function() { if (request.status >= 200 && request.status < 400) { let data = JSON.parse(this.response); // 解析成功就返回Booking实例 resolve(new Booking(data)); } else { // 请求失败抛出错误 reject(new Error(`请求失败,状态码:${request.status}`)); } }; // 处理网络错误 request.onerror = function() { reject(new Error('网络请求出错')); }; request.send(); console.log("Request sent."); }); } // 调用时用async/await(需在async函数内) let button = document.getElementById('button'); button.addEventListener('click', async function() { try { const booking = await getBooking('1'); console.log(booking.id); } catch (err) { console.error('获取预订信息失败:', err); } });
方法二:使用回调函数
如果你暂时不想用Promise,也可以给getBooking传一个回调函数,请求完成后调用这个回调把Booking实例传过去:
function Booking(id, retailer_id, app_date) { this.id = id; this.retailer_id = retailer_id; this.app_date = app_date; } function getBooking(booking_id, callback) { let request = new XMLHttpRequest(); let url = prefix.toString() + 'bookings/' + booking_id; request.open('GET', url, true); request.onload = function() { let data = JSON.parse(this.response); if (request.status >= 200 && request.status < 400) { const booking = new Booking(data.id, data.retailer_id, data.app_date); // 调用回调,传递实例 callback(null, booking); } else { // 出错时传递错误信息 callback(new Error(`请求失败,状态码:${request.status}`)); } }; request.onerror = function() { callback(new Error('网络请求出错')); }; request.send(); console.log("Request sent."); } // 调用时传入回调 let button = document.getElementById('button'); button.addEventListener('click', function() { getBooking('1', function(err, booking) { if (err) { console.error('获取失败:', err); return; } console.log(booking.id); }); });
另外提一句,现在更推荐用fetch API代替XMLHttpRequest,写法更简洁:
function Booking(data) { this.id = data.id; this.retailer_id = data.retailer_id; this.app_date = data.app_date; } async function getBooking(booking_id) { const url = prefix.toString() + 'bookings/' + booking_id; const response = await fetch(url); if (!response.ok) { throw new Error(`请求失败:${response.status}`); } const data = await response.json(); return new Booking(data); } // 调用方式和方法一一致 button.addEventListener('click', async function() { try { const booking = await getBooking('1'); console.log(booking.id); } catch (err) { console.error(err); } });
内容的提问来源于stack exchange,提问作者Joshua Munn
相关产品推荐
相关产品推荐

