全局变量无法通过Ajax请求填充数据的问题排查
嘿,这问题我太熟了——典型的异步JavaScript执行顺序坑!我来给你掰明白为啥你的$jUser一直是空的,再给你俩靠谱的解决方案。
核心问题:Ajax是异步的,你的代码跑太快了
你现在的代码逻辑是这样的:
- 声明全局
$jUser = {} - 绑定登录表单的submit事件
- 立刻执行
console.log($jUser)——这时候登录请求还没触发呢,就算触发了,Ajax请求还在后台和服务器通信,回调里的$jUser = response.authData.user根本还没执行! - 页面加载时的自执行
userSession()函数也是同理:如果是刚登录完刷新页面,你根本没发起验证用户的Ajax请求;就算是登录后立刻执行,验证请求还没返回,$jUser还是空的。
简单说:所有依赖$jUser的代码,都跑到了Ajax回调赋值的前面,自然拿不到数据。
解决方案1:把依赖代码放进Ajax回调里(最直接)
把需要用到$jUser的UI更新逻辑,放到验证用户成功的回调里,确保只有当$jUser被赋值后才执行。我帮你改了代码,还修复了几个小bug(比如event参数不匹配、prop('disabled')没传值):
// Initialize variables var $jUser = {}; var $ajUsers = []; // Login POST $('#frm-login').submit(function (e) { e.preventDefault(); // 这里参数要和函数的e对应,不然会报错 $loginButton.text('Please wait ...').prop('disabled', true); // 禁用按钮要传true $.ajax({ url: "/login-user", type: "POST", data: $('#frm-login').serialize(), dataType: "json" }).always(function (response) { $loginButton.text('Logging in').prop('disabled', false); // 恢复按钮传false console.log("Login", response); if (response.status == "error") { $loginButton.removeClass('lime').addClass('red').text('Log in failed. Try again.'); return; } sessionStorage.setItem('token', response.token); if (sessionStorage.token) { $.ajax({ type: "GET", url: "/verify-user", headers: { 'Authorization': 'Bearer ' + sessionStorage.token }, dataType: "json" }).always(function (response) { console.log("Auth", response); if (response.status == "error") { $loginButton.removeClass('lime').addClass('red').text('Log in failed. Try again.'); return; } $('#index-page').css('display', 'none'); $('#main-page').css('display', 'block'); $jUser = response.authData.user; // 在这里执行需要用$jUser的UI更新逻辑 updateUserProfile(); }); } }); }); // 页面加载时如果有token,先验证用户再更新UI if (sessionStorage.token) { $.ajax({ type: "GET", url: "/verify-user", headers: { 'Authorization': 'Bearer ' + sessionStorage.token }, dataType: "json" }).always(function (response) { console.log("Auth on page load", response); if (response.status == "error") { // 验证失败就清token跳回登录页 sessionStorage.removeItem('token'); $('#main-page').css('display', 'none'); $('#index-page').css('display', 'block'); return; } $jUser = response.authData.user; $('#index-page').css('display', 'none'); $('#main-page').css('display', 'block'); updateUserProfile(); }); } // 把UI更新逻辑封装成函数,复用代码 function updateUserProfile() { $userAvatar.attr('src', $jUser.avatar); $userFullname.text($jUser.first_name + ' ' + $jUser.last_name); console.log('User profile updated!'); }
解决方案2:用Async/Await简化异步逻辑(进阶版)
如果觉得嵌套Ajax回调太乱,可以用async/await把异步代码写成“同步”风格,可读性更强:
// Initialize variables let $jUser = {}; let $ajUsers = []; // 封装验证用户的函数,返回Promise async function verifyUser() { try { const response = await $.ajax({ type: "GET", url: "/verify-user", headers: { 'Authorization': 'Bearer ' + sessionStorage.token }, dataType: "json" }); if (response.status === "error") { throw new Error('User verification failed'); } return response.authData.user; } catch (err) { throw err; } } // Login POST $('#frm-login').submit(async function (e) { e.preventDefault(); $loginButton.text('Please wait ...').prop('disabled', true); try { const loginResponse = await $.ajax({ url: "/login-user", type: "POST", data: $('#frm-login').serialize(), dataType: "json" }); $loginButton.text('Logging in').prop('disabled', false); console.log("Login", loginResponse); if (loginResponse.status === "error") { $loginButton.removeClass('lime').addClass('red').text('Log in failed. Try again.'); return; } sessionStorage.setItem('token', loginResponse.token); $jUser = await verifyUser(); $('#index-page').css('display', 'none'); $('#main-page').css('display', 'block'); updateUserProfile(); } catch (err) { $loginButton.removeClass('lime').addClass('red').text('Log in failed. Try again.'); console.error(err); } }); // 页面加载时验证用户 if (sessionStorage.token) { (async function() { try { $jUser = await verifyUser(); $('#index-page').css('display', 'none'); $('#main-page').css('display', 'block'); updateUserProfile(); } catch (err) { sessionStorage.removeItem('token'); $('#main-page').css('display', 'none'); $('#index-page').css('display', 'block'); console.error(err); } })(); } function updateUserProfile() { $userAvatar.attr('src', $jUser.avatar); $userFullname.text($jUser.first_name + ' ' + $jUser.last_name); console.log('User profile updated!'); }
几个额外小提醒
- 记得处理验证失败的情况(比如token过期),不然用户可能会看到空白的个人信息
- 尽量避免滥用全局变量,不过这里为了兼容你的现有代码暂时保留了
- jQuery的
$.ajax其实本身就支持Promise,所以可以直接用await
内容的提问来源于stack exchange,提问作者July333
相关产品推荐
相关产品推荐

