首页 > 解决方案 > 如何确定 jquery ajax 调用何时完成?

问题描述

我有一个国家的下拉列表,并有一个 jquery ajax 调用,它使用国家名称填充下拉列表。问题是我需要知道通话何时完成,然后才能确定选择哪个国家/地区。也就是说,我在使用 ajax 调用的函数之后调用的任何函数都被调用得太快(在填充下拉列表之前),所以下面的函数会崩溃。我也不想使用 async=false (因为这会导致更多问题并且是不好的做法)。实现这一目标的正确方法是什么?

这是一个通用的 ajax 函数,用于检索数据并使用参数 id 填充特定类型的选择下拉列表 (ddl):

   function RetrieveDD(ddl, ddtype, id) {
        var servicename;
        switch (ddtype) {
            case 'country':
                servicename = "LoadCountries";
                break;
            case 'state':
                servicename = "LoadStateProvinces";
                break;
            case 'city':
                servicename = "LoadCityLocalities";
                break;
            default:
                servicename = "";
        }
        if (servicename != "") {
             $.ajax({
                url: 'DDService.asmx/' + servicename,
                dataType: 'json',
                method: 'post',
                data: { ID: id },
                success: function (data) {
                    ddl.empty();
                    $.each(data, function (index) {
                        ddl.append($("<option" + (index == 0 ? " selected" : "") + "></option>").val(this['V']).html(this['T']));
                    });
                },
                error: function (err) {
                    console.log('Error (RetrieveDD): ' + JSON.stringify(err, null, 2));
                }
            });
        };
    };

我有一个执行此操作的测试按钮,并希望获取所选选项的值(它将调用填充状态,获取第一个选定状态的值并再次调用以填充城市)。问题很明显:我不能在不知道前一个下拉列表的选定值的情况下说填充下一个下拉列表(所以我必须有办法等待下拉列表首先填充)。

        $('#btnTest').click(function () {
           RetrieveDD($("#ddlCountries"), "country", 0);

            var cid = $("#ddlCountries").val();  //this is still undefined because ajax call above not completed 
            alert("cid = " + cid);    //normally another call would be made here to populate the states
        });

单击该按钮时,您会立即看到一个警报框弹出(没有 cid 值),并且在您单击警报对话框中的 [Okay] 按钮之前不会填充国家下拉列表。基本上顺序不对。

如果我将async:false添加到 ajax 例程中,您将看到显示正确 cid 的警报,但是,正如人们发布的那样,您永远不应该使用async:false。我希望避免这种情况,但不确定如何正确执行此操作。(如果有人想知道,我将从旧的 dotnet webforms 网站中删除所有 MSAjaxToolkit 废话,并用 jQuery ajax 代替——它更快、更小、更容易修复。)

这是 HTML 片段

    <input type="button" id="btnTest" value="Test" /><br />
    <div id="dd">
        <select id="ddlCountries"></select><br />
        <select id="ddlStates"></select><br />
        <select id="ddlCities"></select>
    </div>

************** 回应为什么我认为这不是重复 ********* 需要添加对旧版 IE 支持的要求(Windows 7 附带, 8, 8.1 和一些服务器版本)。IE 不支持箭头函数或承诺(或 2015 年之后的大多数 ECMA 方法),因此许多推荐的答案虽然非常好,但并未包含此类代码。我会尝试解决这个问题并在这里发布。

标签: javascriptjqueryhtmlajax

解决方案


JQuery.ajax() 实现了 Promise 接口,因此您可以获取 ajax 调用返回的 Promise 对象并将其传递回您的调用函数。可以在ajax调用完成后使用Promise.then()调用代码,我认为这比使用回调更简洁。

   function RetrieveDD(ddl, ddtype, id) {
    var servicename;
    var promise;
    switch (ddtype) {
        case 'country':
            servicename = "LoadCountries";
            break;
        case 'state':
            servicename = "LoadStateProvinces";
            break;
        case 'city':
            servicename = "LoadCityLocalities";
            break;
        default:
            servicename = "";
    }
    if (servicename != "") {
         promise = $.ajax({
            url: 'DDService.asmx/' + servicename,
            dataType: 'json',
            method: 'post',
            data: { ID: id },
            success: function (data) {
                ddl.empty();
                $.each(data, function (index) {
                    ddl.append($("<option" + (index == 0 ? " selected" : "") + "></option>").val(this['V']).html(this['T']));
                    console.log('update list');
                });
            },
            error: function (err) {
                console.log('Error (RetrieveDD): ' + JSON.stringify(err, null, 2));
            }
        });
    };

    return promise;
};


$('#btnTest').click(function () {
    var promise = RetrieveDD($("#ddlCountries"), "country", 0);
    if (promise) {
        promise.then(function(value) {
            var cid = $("#ddlCountries").val();                  
            console.log('done');
        });
    }
});

推荐阅读