如何解决AJAX异步调用延迟导致函数返回null的问题?
问题原因
- AJAX异步执行特性:
$.ajax默认是异步请求,发送请求后不会阻塞后续代码执行,getLocationData函数会在AJAX请求还没拿到响应的时候就直接执行结束。你在done回调里写的return语句,返回的是done这个回调函数的返回值,根本不是getLocationData的返回值,getLocationData本身没有显式写返回,默认返回undefined,所以你赋值的locationData自然是空的。 - 执行顺序逻辑:JS执行异步任务时会把回调放到事件队列,先执行完主线程的所有同步代码,才会去执行事件队列里的异步回调。所以你点击事件里的
console.log是同步代码,会先执行,等主线程空闲、AJAX请求拿到响应后,才会执行done里的console.log,就出现了你看到的顺序颠倒的情况。 - 拼写错误:你定义的函数名是
getLocationData,但是点击事件里调用的时候写的是getLocationsData,多了一个s,也会导致调用报错拿不到返回值。
解决方法
推荐用Promise + async/await的方案改造代码,逻辑更清晰:
- 改造
getLocationData函数,让它返回Promise实例
const baseUrl = 'https://booking-com.p.rapidapi.com/v1/hotels/'; var locale = "en-gb"; function getLocationData(){ return new Promise((resolve, reject) => { var destination = {}; var location = $('#location').val(); var route = ""; // 原逻辑||改为&&,避免空字符串也生成请求路径 if(location != null && location != ""){ // 对用户输入做URL编码,避免特殊字符导致请求报错 route = `locations?locale=${locale}&name=${encodeURIComponent(location)}`; } console.log(`${baseUrl}${route}`); $.ajax({ method: "GET", url: `${baseUrl}${route}`, headers:{ 'x-rapidapi-host': 'booking-com.p.rapidapi.com', 'x-rapidapi-key': 'api-key' } }) .done(response => { if(response[0]["dest_type"] != "hotel"){ destination = { "label":response[0]["label"], "dest_id": response[0]["dest_id"], "dest_type": response[0]["dest_type"] }; } console.log("getLocationData()", destination); resolve(destination); }) .fail(response => { console.log("ajax failed",response); reject(response); }); }) }
- 改造点击事件,用
async/await等待异步请求结果
// 回调函数前加async关键字,支持内部使用await $('#search-hotels').click(async function () { let dateRange = getDateRangeObject(); let checkin = dateRange['checkin']; let checkout = dateRange['checkout']; let isCheckinInvalid = moment(checkin).isBefore(moment(new Date()).format('YYYY-MM-DD')); let isCheckoutInvalid = moment(checkout).isBefore(moment(new Date()).add(1, 'days').format('YYYY-MM-DD')); let adults = $('#adults').val(); let rooms = $('#rooms').val(); let isAdultsAndRoomValid = adults >= 1 && rooms >= 1; // 加await等待请求返回,同时修正函数名拼写错误 let locationData = await getLocationData(); let destination = {...locationData}; console.log("click button function",destination); // 原逻辑缺少location变量定义,补充获取输入框值 let location = $('#location').val(); if (location != "" && !isCheckinInvalid && !isCheckoutInvalid && isAdultsAndRoomValid) { window.location.href = `hotels.html?location=${encodeURIComponent(location)}&checkin=${checkin}&checkout=${checkout}&adults=${adults}&rooms=${rooms}`; } return false; });
内容的提问来源于stack exchange,提问作者Enchantres
相关产品推荐
相关产品推荐

