jQuery - 等待所有嵌套的 ajax 和每个调用完成

jQuery - wait for all nested ajax and each calls to complete

在继续之前,我似乎无法完成 JavaScript 到 运行 的这一点。在 ajax 中有一个 each,它本身在 ajax.

的 each 内部

每次我在 Chrome 中加载它(并在我的评论 "I don't want this to happen until..." 处设置一个断点),它会在我的 htmlDivs 集合中包含任何内容之前到达我的断点。继续之后,htmlDivs 集合总是被填满,这让我相信我在尝试使用下面的 promises 和 .done() 时做错了什么。

代码最能说明这一点:

var htmlDivs = {};

function SelectTopLevelThingFromPage(id) {
    SetupHtmlDivs(id).done(
        function () {
            // I don't want this to happen until SetupHtmlDivs() completes
            // (including all nested $.each and $.ajax)
            var keys = Object.keys(htmlDivs);
            // Append the htmlDivs in a specific sorted order
        }
    );
}

function SetupHtmlDivs(id) {
    var promises = [];

    $.ajax({
        url: "api/GetSecondLevelThingsFromTopLevelId" + id,
        method: "get",
        success: function (SecondLevelThings) {
            $.each(SecondLevelThings, function (i, SecondLevelThing) {
                var promise = SetupHtmlForOneThing(SecondLevelThing);
                promises.push(promise);
            });
        }
    });

    return $.when.apply($, promises).promise();
}

function SetupHtmlForOneThing(SecondLevelThing) {
    var promises = [];

    $.ajax({
        url: "api/SecondLevelThing/" + SecondLevelThing.id + "/Environments",
        method: "get",
        success: function (Environments) {
            $.each(Environments, function (k, env) {
                var def = new $.Deferred();
                promises.push(def);
                htmlDivs[SecondLevelThing.id + "-" + env] = SecondLevelThing;
                def.resolve();
            });
        }
    });

    return $.when.apply($, promises).promise();
}

尝试以下操作:

var htmlDivs = {};

function SelectTopLevelThingFromPage(id) {
    SetupHtmlDivs(id).done(
        function () {
            // I don't want this to happen until SetupHtmlDivs() completes
            // (including all nested $.each and $.ajax)
            var keys = Object.keys(htmlDivs);
            // Append the htmlDivs in a specific sorted order
        }
    );
}

function SetupHtmlDivs(id) {

    var finalPromise = new $.Deferred();
    $.ajax({
        url: "api/GetSecondLevelThingsFromTopLevelId" + id,
        method: "get",
        success: function (SecondLevelThings) {
            var promises = [];
            $.each(SecondLevelThings, function (i, SecondLevelThing) {
                var promise = SetupHtmlForOneThing(SecondLevelThing);
                promises.push(promise);
            });

            $.when.apply($, promises).then(function() {
                finalPromise.resolve();
            });
        }
    });

    return finalPromise;
}

function SetupHtmlForOneThing(SecondLevelThing) {
    var innerPromise = new $.Deferred();
    $.ajax({
        url: "api/SecondLevelThing/" + SecondLevelThing.id + "/Environments",
        method: "get",
        success: function (Environments) {
            $.each(Environments, function (k, env) {
                htmlDivs[SecondLevelThing.id + "-" + env] = SecondLevelThing;
            });
            innerPromise.resolve();
        }
    });

    return innerPromise;
}

最大的变化是:

  • 内部函数 SetupHtmlForOneThing 在 ajax 调用中不需要承诺,因为这是 success 回调中的 non-ajax 操作。它只需要解决它自己提供的单一承诺。
  • 外部函数 SetupHtmlDivs 只需要一个 promise,当所有生成的内部 promise 都完成时,该 promise 就会被解析。