You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

全局变量无法通过Ajax请求填充数据的问题排查

嘿,这问题我太熟了——典型的异步JavaScript执行顺序坑!我来给你掰明白为啥你的$jUser一直是空的,再给你俩靠谱的解决方案。

核心问题:Ajax是异步的,你的代码跑太快了

你现在的代码逻辑是这样的:

  1. 声明全局$jUser = {}
  2. 绑定登录表单的submit事件
  3. 立刻执行console.log($jUser)——这时候登录请求还没触发呢,就算触发了,Ajax请求还在后台和服务器通信,回调里的$jUser = response.authData.user根本还没执行!
  4. 页面加载时的自执行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:13:07