如何等待Ajax请求?

44

我正在尝试编写JS代码,如果给定的数字已存在于数据库中,则取消“btn_submit”按钮的.onclick事件。我使用AJAX查询给定数字的DB,并确定是否应将数据发送到.php网站,该网站将上传问题。为了确定这一点,我需要numOfRows变量的值,但由于我在AJAX中设置它,它将保持为0。验证()函数将在我的AJAX查询完成之前完成,这会导致问题,始终声明给定数字不存在于DB中(numOfRows将始终保持为0)。如何在比较validation()函数末尾行的numOfRows与0之前等待AJAX查询完成?如果数字已经存在于DB中,我需要返回false到此行:

document.getElementById("btn_submit").onclick = validation;

谢谢!

var textAreaList;
var numOfRows = 0;
var finished = false;

document.getElementById("btn_submit").onclick = validation;

textAreaList = document.getElementsByClassName("text_input");

function validation() {
    loadNumRows();

    try {
        document.getElementById('failure').hidden = true;
    }
     catch(e) {
         console.log(e.message);
     }
    textAreaList = document.getElementsByClassName("text_input");
    var failValidation = false;
    for (var i = 0; i < textAreaList.length; i++) {
        console.log(textAreaList[i]);
        if (textAreaList[i].value == "") {
            textAreaList[i].style.border = "2px solid #ff0000";
            failValidation = true;
        } else {
            textAreaList[i].style.border = "2px solid #286C2B";
        }
    }

    return !(failValidation || numOfRows != 0);
}

function loadNumRows(){
    $.ajax({
        url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
        type: "GET",
        cache: false,
        success: function (html) {
           numOfRows = parseInt(html);               
        }
    });
}

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - charlietfl
这个回答解决了你的问题吗?如何从异步调用中返回响应? - Henke
5个回答

47

使用类似 Babel 的转译器与 async/await 一起,以在旧版浏览器中正常工作。您还需要从 npm 安装此 Babel 预设和 polyfill:

npm i -D babel-preset-env babel-polyfill

那么

function getData(ajaxurl) { 
  return $.ajax({
    url: ajaxurl,
    type: 'GET',
  });
};

async function test() {
  try {
    const res = await getData('https://api.icndb.com/jokes/random')
    console.log(res)
  } catch(err) {
    console.log(err);
  }
}

test();

或者说.then回调函数只是另一种编写相同逻辑的方式。

getData(ajaxurl).then((res) => {
    console.log(res)
});

2
注意:使用最新的 CRA,不再需要 babel-polyfill - Murtaza Hussain

18

使用async: false是非常糟糕的想法,并且违背了使用AJAX的初衷——AJAX本来就是为异步而设计的。如果你想要在发出AJAX调用时等待脚本响应,只需使用延迟对象和承诺:

var validation = function () {
    var numberCheck = $.ajax({
        url: 'php/SeeIfNumberExists?number=' + $('#number_inp').val(),
        type: "GET"
    });

    // Listen to AJAX completion
    numberCheck.done(function(html) {
        var numOfRows = parseInt(html),
            textAreaList = $('.text_input'),
            finished = false;

        // Rest of your code starts here
        try {
            document.getElementById('failure').hidden = true;
        }
        catch(e) {
            console.log(e.message);
        }

        // ... and the rest
    });

}

// Bind events using jQuery
$('#btn_submit').click(validation);

我在你的代码中看到你同时使用了原生JS和jQuery - 如果你坚持使用其中一种,会更有帮助 :)


1
将ajax请求存储在变量中并使用.done是否比仅提供successerror方法有任何优势? - developerwjk
2
@developerwjk jqXHR.success()方法已于v1.8正式弃用。请改用jqXHR.done(),因为$.ajax()已经原生实现了promises,当从服务器接收到响应时将返回一个解决延迟对象。已解决的对象将映射到.done(),而被拒绝的对象将映射到.fail()。两者都将映射到.always() - Terry

14

永远不要使用async:false,它很危险,会导致您的应用程序表现异常。

只有在响应返回Promise时才能使用await。

不幸的是,当jQuery ajax完成时,它不会返回Promise。

但是您可以在ajax请求中使用Promise,在完成时返回Promise。

function asyncAjax(url){
    return new Promise(function(resolve, reject) {
            $.ajax({
                url: url,
                type: "GET",
                dataType: "json",
                beforeSend: function() {            
                },
                success: function(data) {
                    resolve(data) // Resolve promise and when success
                },
                error: function(err) {
                    reject(err) // Reject the promise and go to catch()
                }
            });
    });
}

我们已经将 AJAX 调用转换为 Promise,因此现在可以使用 await。

try{
    const result = await asyncAjax('your url');
} catch(e){
    console.log(e);
}

避免使用Promise构造反模式!jQuery延迟对象已经是可await的,您可以直接使用它们。或者如果您绝对需要一个本地的promise,只需使用Promise.resolve(…)即可。 - Bergi
从哪里得到的信息?据我所知,这并不正确。虽然它会阻塞用户界面,但只要你意识到这个副作用,它并不是本质上的危险。 - Clonkex

5

这对我起作用

async function doAjax() {
    const result = await $.ajax({
        url: "https://api.exchangerate-api.com/v4/latest/USD",
        type: 'GET',
    });

    return result;
}

async function tt(){
    var res = await doAjax()
    var money = res.rates.INR
    console.log(money)
}

tt()

2

(我承认这不是最好的方法,但这是让您的代码快速运行的最快方法。 但是,您应该重新考虑如何提取numOfRows值,以便它可以与真正的异步Ajax一起使用。 尽管如此...):

首先,在$.ajax调用中设置async : false。 Ajax中的A代表异步。 这意味着执行会继续而不是等待返回。 您希望关闭它(即使其成为同步)。 实际上,这应该是您现有代码的整个解决方案。

$.ajax({
        url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
        type: "GET",
        async: false,
        cache: false,
        success: function (html) {
           numOfRows = parseInt(html);               
        }
    });

来自$.ajax文档的一个警告:
跨域请求和dataType: "jsonp"请求不支持同步操作。请注意,同步请求可能会暂时锁定浏览器,禁用任何在请求活动期间执行的操作。从jQuery 1.8开始,使用async: false与jqXHR ($.Deferred)已被弃用;您必须使用成功/错误/完成回调选项来代替jqXHR对象的相应方法,如jqXHR.done()或jqXHR.success()(已弃用)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接