如何等待进行异步调用的.each循环?

时间:2015-04-17 17:26:42

标签: javascript jquery

我有一些javascript代码使用http处理程序将一些数据更新到数据库,但是此异步调用是在.each循环内进行的。在循环结束时,我调用了刷新页面的函数CancelChanges()。问题是在更新数据库之前页面似乎刷新了。调用.each后,CancelChanges()循环似乎已完成。在.each循环中完成所有异步调用后,如何确保刷新页面?

function SaveChanges() {
    if (PreSaveValidation()) {
        var allChangesSucceeded = true;
        var studioId = $("#param_studio_id").val();
        var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
        var currency = "CAD";
        var vacationPct = null;
        var gvAdmissible = null;

        $(".editable-unsaved").each( function() {
            var newSalary = $(this).text();
            var disciplineId = $(this).data("disciplineid");
            var seniorityId = $(this).data("seniorityid");
            var handlerCommand = "";
            if ($(this).data("valuetype") === "inflated") {
                handlerCommand = "AddAverageSalary";
            } else if ($(this).data("valuetype") === "actual") {
                handlerCommand = "UpdateAverageSalary";
            }
            $.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
                if (data != "1") {
                    $(this).removeClass("editable-unsaved");
                    allChangesSucceeded = true;
                }
                else {
                    alert('fail');
                    allChangesSucceeded = false;
                }
            });
        });
        if(allChangesSucceeded) CancelChanges();
    }
}

function CancelChanges() {
    var href = window.location.href;
    href = href.split('#')[0];
    window.location.href = href;
}

5 个答案:

答案 0 :(得分:6)

您可以尝试使用PromisesjQuery $.when

存储ajax调用promises的列表:

var defereds = [];

$(".editable-unsaved").each( function() {
    //...
    defereds.push($.get("WS/AverageSalary.ashx" /*...*/));
}
$.when.apply($, defereds).done(function() {
    CancelChanges();
});

希望等待所有ajax调用完成后再调用CancelChanges()

答案 1 :(得分:2)

我认为您需要稍微更改一下结构,使用计数器并在计数器等于调用次数时调用CancelChanges。

function SaveChanges() {
    if (PreSaveValidation()) {
        var studioId = $("#param_studio_id").val();
        var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
        var currency = "CAD";
        var vacationPct = null;
        var gvAdmissible = null;

        var editableUnsaveds = $(".editable-unsaved"); //cache the selector here, because selectors are costly
        var numOfGetsReturned = 0;            

        editableUnsaveds.each( function() {
            var newSalary = $(this).text();
            var disciplineId = $(this).data("disciplineid");
            var seniorityId = $(this).data("seniorityid");
            var handlerCommand = "";
            if ($(this).data("valuetype") === "inflated") {
                handlerCommand = "AddAverageSalary";
            } else if ($(this).data("valuetype") === "actual") {
                handlerCommand = "UpdateAverageSalary";
            }
            $.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
                if (data != "1") {
                    $(this).removeClass("editable-unsaved");
                }
                else {
                    alert('fail');
                }
                if(editableUnsaveds.length === ++numOfGetsReturned){
                   CancelChanges(); //now it should call when the final get call finishes.
                }
            });
        });
    }
}

function CancelChanges() {
    var href = window.location.href;
    href = href.split('#')[0];
    window.location.href = href;
}

答案 2 :(得分:1)

我使用promisesq library是我最喜欢的实现方法。但是,既然您正在使用JQuery,我建议您按照与我在下面概述的方法类似的方法,但使用$.when,而不是q.allSettled

我经常在同时抓取大量网站时使用承诺 - 我需要遍历一长串网站,发出内容请求,并在请求返回时对内容执行某些操作。我要做的最后一件事是一次发送一个请求,在返回时处理每个请求。

在摘要中,看起来像这样:

function scrapeFromMany() {
  var promises = [];

    _.forEach(urls, function(url) {

      // this makes the request
      var promise = scraper(url);

      // this stores the promise with the others you iterate through
      promises.push(promise); 
    });

  q.allSettled(promises).then(function(res) {
    // this function is executed when all of the promises (requests) have been resolved 

   console.log("Everything is done -- do something with the results.", res);
  });
}

Fwiw,如果你从未使用它们,那么承诺并不容易。如果是这种情况,请计划花一些时间来熟悉这些概念。它们会改变(为了更好)你编写异步javascript的方式,而且它们确实是这些操作的有福路径。

答案 3 :(得分:0)

在"完成"内异步调用您的支票功能。函数处理程序跟踪已完成的请求数量,并且仅在预期请求总数等于您的处理时进行处理。

if (PreSaveValidation()) {
    var allChangesSucceeded = true;
    var length = $(".editable-unsaved").length;
    var completedCount = 0;
    // ...

    $(".editable-unsaved").each( function() {
        // ...
        $.get("WS/AverageSalary.ashx", data).done(function (data) {

            completedCount++;

            if (data != "1") {
                $(this).removeClass("editable-unsaved");
                // don't set all changes succeeded to true here
            }
            else {
                alert('fail');
                allChangesSucceeded = false;
            }

            isComplete(length, completedCount, allChangesSucceeded);
        });
    });
}

function isComplete(totalLength, currentLength, allChangesSucceeded) {
    if (currentLength == totalLength) {

        // should this be !allChangesSucceeded?
        if (allChangesSucceeded) CancelChanges();
    }
}

答案 4 :(得分:0)

这是因为您没有等待请​​求完成以继续循环。 要实现这一点,您必须将“async”标志设置为false。 对服务器的调用应该是这样的:


    $.ajax({
        url: "WS/AverageSalary.ashx",
        async: false,
        data:{ command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible },
        success: function (data) {
            if (data != "1") {
                $(this).removeClass("editable-unsaved");
                allChangesSucceeded = true;
            }
            else {
                alert('fail');
                allChangesSucceeded = false;
            }
        }
    });