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

如何从异步ajax方法中正确获取返回值

问题根源

你始终拿到undefined的核心原因有两点:

  • 回调函数内部的return只会终止回调函数自身的执行、返回值到回调的调用位置,不会向外层的setAvailableQuestions函数返回值,所以外层函数拿不到结果
  • 你写的同步请求版本逻辑顺序错误:同步请求不需要绑定onreadystatechange事件,事件回调里的返回值同样不会被外层函数接收,自然拿到undefined
可行解决方案

方案1:沿用原有回调封装,直接在回调内写业务逻辑

这是改动最小的方案,不需要修改你已经写好的ajaxRequest封装,只需要把依赖请求结果的逻辑全部放到回调函数内部执行,不要尝试在外层接返回值:

// 原有ajaxRequest封装无需改动
function ajaxRequest(type,url,callback,data=""){
    let request = new XMLHttpRequest();
    request.open(type, url);

    request.onload = function () {
        switch (request.status){
            case 200:
            case 201:
                    callback(request.responseText);
            break;
            default: console.log(request.status);
        }
    };
    request.send(data);
}

function getNewQuestion(){
    // 直接把数据处理逻辑作为回调传入
    ajaxRequest("GET","../controller.php?func=get_availableQuestion", (questions) => {
        const availableQuestions = JSON.parse(questions);
        console.log(availableQuestions); // 此处可以正常拿到解析后的数据
        // 所有需要用到availableQuestions的业务逻辑,全部写在这个回调内部
    });
}

注意:不要在回调函数外部写依赖请求结果的代码,ajax默认是异步执行,回调外的代码会在请求还没返回时就提前运行,必然拿不到值。

方案2:封装Promise,配合async/await写法

这就是你提到的.then/await实现方案,把ajax请求封装成Promise实例后,就可以用同步写法写异步逻辑,避免回调嵌套:

// 改造ajaxRequest为Promise版本
function ajaxRequest(type,url,data=""){
    return new Promise((resolve, reject) => {
        let request = new XMLHttpRequest();
        request.open(type, url);

        request.onload = function () {
            switch (request.status){
                case 200:
                case 201:
                    resolve(request.responseText); // 请求成功把结果传给resolve
                    break;
                default:
                    reject(new Error(`请求异常,状态码:${request.status}`));
            }
        };
        request.onerror = () => reject(new Error("网络连接失败"));
        request.send(data);
    })
}

// 用async标记函数,内部用await等待请求结果
async function getNewQuestion(){
    try {
        const questionStr = await ajaxRequest("GET","../controller.php?func=get_availableQuestion");
        const availableQuestions = JSON.parse(questionStr);
        console.log(availableQuestions); // 正常拿到数据
        // 后续业务逻辑直接往下写即可,不需要嵌套回调
    } catch (err) {
        console.error("获取题目失败:", err);
    }
}

// 调用函数即可执行
getNewQuestion();

你之前写的同步请求为什么不生效?

同步请求的执行逻辑是request.send()调用后会阻塞后续代码执行,直到请求完成,所以不需要绑定状态监听事件,直接在send之后读取响应即可。你之前把解析逻辑写在onreadystatechange回调里,return的值只会留在回调作用域,外层函数拿不到。
正确的同步写法参考(不推荐实际使用):

// 同步请求会在请求过程中锁死整个页面,用户无法做任何交互,体验极差,仅做原理演示
function setAvailableQuestions(){
    const ajax = new XMLHttpRequest();
    // 第三个参数传false代表同步请求
    ajax.open("GET","../controller.php?func=get_availableQuestion", false);
    ajax.send();
    if(ajax.status === 200 || ajax.status === 201) {
        return JSON.parse(ajax.response);
    }
    console.log("请求失败,状态码:", ajax.status);
    return null;
}

function getNewQuestion(){
    const availableQuestions = setAvailableQuestions();
    console.log(availableQuestions);
}

日常开发优先用前两种异步方案,不要用同步请求。


内容的提问来源于stack exchange,提问作者chubby marschmallow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:54:29