为何JS函数无法为变量赋值?XMLHttpRequest异步问题排查
问题描述
我编写了一个获取用户兴趣的JS函数,调用后发现console.log(interest1)和return语句前的alert(customerInterest)都无法获取到值,但request.onload回调里的alert("---"+customerInterest)能正常显示预期结果。
我的JS函数代码
function interest(customerRef) { try { var customerInterest = ""; var baseUrl="https://test/" var url = baseUrl+customerRef var username = "username"; var password = "password"; var request = new XMLHttpRequest(); request.open("GET", url); request.setRequestHeader("Authorization", "Basic " + btoa(username+":"+password)) request.send() request.onload=()=> { if(request.status==200) { var guestJson = JSON.parse(request.response); var sessions = guestJson.sessions || []; var interest = sessions.filter(session => session.events) .flatMap(session => session.events) .filter(event => event.type === "SEARCH") .map(event => event.arbitraryData.interest)[0]; customerInterest = interest; alert("---"+customerInterest); } else { console.log(`error ${request.status} ${request.statusText}`) } } alert(customerInterest); return customerInterest; } catch (error) { console.error(error); } }
HTML调用代码
customerRef = "6a789727" var interest1 = ""; interest1 = interest(customerRef); console.log(interest1);
问题原因
这是异步请求的执行顺序问题:XMLHttpRequest.send()是异步操作,代码不会等待请求完成才继续执行后续逻辑。函数里的alert(customerInterest)和return customerInterest会在网络请求还未返回、onload回调尚未执行时就运行,此时customerInterest还是初始的空字符串。而onload回调要等请求成功返回后才会触发,这时候才会给customerInterest赋值,所以内部的alert能拿到正确值。
解决方案
方案1:用Promise封装函数(推荐)
将函数改为返回Promise,调用时通过async/await或then获取异步结果:
function interest(customerRef) { return new Promise((resolve, reject) => { try { const baseUrl="https://test/" const url = baseUrl + customerRef const username = "username"; const password = "password"; const request = new XMLHttpRequest(); request.open("GET", url); request.setRequestHeader("Authorization", "Basic " + btoa(username+":"+password)) request.send() request.onload = () => { if(request.status === 200) { const guestJson = JSON.parse(request.response); const sessions = guestJson.sessions || []; const interest = sessions.filter(session => session.events) .flatMap(session => session.events) .filter(event => event.type === "SEARCH") .map(event => event.arbitraryData.interest)[0]; alert("---"+interest); resolve(interest); // 请求成功时返回结果 } else { const errorMsg = `error ${request.status} ${request.statusText}`; console.log(errorMsg); reject(new Error(errorMsg)); // 请求失败时抛出错误 } } request.onerror = () => { const errorMsg = "请求发生网络错误"; console.error(errorMsg); reject(new Error(errorMsg)); } } catch (error) { console.error(error); reject(error); } }); }
调用方式(async/await)
async function getCustomerInterest() { const customerRef = "6a789727" const interest1 = await interest(customerRef); console.log(interest1); } getCustomerInterest();
调用方式(then回调)
const customerRef = "6a789727" interest(customerRef).then(interest1 => { console.log(interest1); }).catch(error => { console.error(error); });
方案2:使用回调函数
在函数参数中传入回调,请求完成后通过回调返回结果:
function interest(customerRef, callback) { try { const baseUrl="https://test/" const url = baseUrl + customerRef const username = "username"; const password = "password"; const request = new XMLHttpRequest(); request.open("GET", url); request.setRequestHeader("Authorization", "Basic " + btoa(username+":"+password)) request.send() request.onload = () => { if(request.status === 200) { const guestJson = JSON.parse(request.response); const sessions = guestJson.sessions || []; const interest = sessions.filter(session => session.events) .flatMap(session => session.events) .filter(event => event.type === "SEARCH") .map(event => event.arbitraryData.interest)[0]; alert("---"+interest); callback(null, interest); // 成功时传入null和结果 } else { const errorMsg = `error ${request.status} ${request.statusText}`; console.log(errorMsg); callback(new Error(errorMsg), null); // 失败时传入错误 } } request.onerror = () => { const errorMsg = "请求发生网络错误"; console.error(errorMsg); callback(new Error(errorMsg), null); } } catch (error) { console.error(error); callback(error, null); } }
调用方式
const customerRef = "6a789727" interest(customerRef, (error, interest1) => { if (error) { console.error(error); return; } console.log(interest1); });
内容的提问来源于stack exchange,提问作者Jey
相关产品推荐
相关产品推荐

