【问题标题】:Ajax call in for loop wait until ALL done (error or success)Ajax 调用 for 循环等待所有完成(错误或成功)
【发布时间】:2015-09-25 17:13:15
【问题描述】:

我在 for 循环中进行 AJAX 调用,我想等到所有调用都完成后再做某事。

我正在尝试使用 Promise,但我缺少一些东西,因为它不起作用。如果触发错误,我的when 调用会立即触发,我不想这样做。我想等到所有调用都完成,无论是成功还是错误。

所有调用完成后,我想要成功的条目数和错误数组。

这是我的代码:

for (var i = 0; i < resp.propertiesList.length; i++) {
    var documentToSend = { 
        indexName: indexName, 
        type: type, 
        jsonContent: blabla 
    };

    var promise = _TOOLS.Ajax({
        type: 'POST',
        url: urlTest,
        data: documentToSend,
        contentType: 'application/x-www-form-urlencoded',
        dataType: 'json',
        success: function (dataResponse) {
            numberOfEntriesSuccess++;
        },
        error: function (xhr, ajaxOptions, errorThrown) {
            var errorResponse = JSON.parse(xhr.responseText);
            errorsList.push(errorResponse.ExceptionMessage + ". Skipping line.");
        }
    });

    promises.push(promise);
}

//When all ajax calls are finished, load report page and display informations
$.when.apply($, promises).done(function() { 
    console.log("DONE " + promises.length); 
    console.log(errorsList); 
})

我尝试过使用.done.then.always,但是当我愿意时,它们都没有触发。 我在互联网上阅读了很多关于承诺的内容,但我肯定错过了一些东西,这让我发疯了。

感谢您的帮助!

【问题讨论】:

  • 这是(很不幸)when() 的工作方式——即。一旦 1 个请求失败,它就会立即跳转到错误处理程序并停止处理进一步的请求。唯一真正的替代方法是从 jQuery 源代码原型/创建 $.when 的替代版本,该版本在错误时静默失败。

标签: javascript jquery ajax promise


【解决方案1】:

我发现最容易处理这些事情的方法是跟踪对象或数组中每个 Async 调用的状态。每次调用完成时,将其标记为已完成并检查是否还有其他正在运行。您甚至可以在对象中添加一个布尔值来检查 asyncIsBusyajaxStatus 的属性。

我在这里假设indexNametype 来自resp.propertiesList(你似乎没有在任何地方使用你的i,所以我猜你是不小心把它漏掉了?)。

for (var i = 0; i < resp.propertiesList.length; i++) {
    var documentToSend = { 
        indexName: indexName, 
        type: type, 
        jsonContent: blabla 
    };

    sendDocumentAjax(resp.propertiesList[i], documentToSend)
}

function sendDocumentAjax(listObj, documentData){
    listObj.ajaxStatus = 'pending';
    _TOOLS.Ajax({
        type: 'POST',
        url: urlTest,
        data: documentData,
        contentType: 'application/x-www-form-urlencoded',
        dataType: 'json',
        success: function (dataResponse) {
            listObj.ajaxStatus = 'success';
        },
        error: function (xhr, ajaxOptions, errorThrown) {
            var errorResponse = JSON.parse(xhr.responseText);
            listObj.ajaxStatus = 'error: '+ errorResponse;
        }
        always: checkAjaxStatuses;
    });
}

function checkAjaxStatuses(){
    var pending = [];
    var successes = [];
    var errors = [];
    for (var i = 0; i < resp.propertiesList.length; i++) {
        if(resp.propertiesList[i].ajaxStatus === 'pending'){
            pending.push(resp.propertiesList[i]);
        }
        if(resp.propertiesList[i].ajaxStatus === 'success'){
            successes.push(resp.propertiesList[i]);
        }
        if(resp.propertiesList[i].ajaxStatus.indexOf('error') !== -1){
            errors.push(resp.propertiesList[i]);
        }
    }

    console.log('ajax completed.');
    console.log(pending.length + ' pending.');
    console.log(successes.length + ' succeeded.');
    console.log(errors.length + ' failed.');
}

请注意我是如何使用单独的函数来发送 ajax 的,因此会为您发送 ajax 调用的每个对象创建一个新的闭包。您不能通过匿名函数完成所有这些操作,因为i 始终是回调中的最大值(因为循环在任何 ajax 调用完成之前完成),因此您无法引用发送 Ajax 的原始对象为了。使用单独的函数可以避免这个问题。

【讨论】:

  • 是的,很抱歉我不小心漏掉了一些东西。谢谢,我会试试这个,这似乎是个好主意
  • 没问题,意图很清楚:) 告诉我进展如何。
【解决方案2】:

Q.allSettled 可以帮助你,你可以在这里找到 npm 包 - https://www.npmjs.com/package/q

【讨论】:

    【解决方案3】:

    尝试在 ajax 调用中设置 async: false

    var promise = _TOOLS.Ajax({
                        type: 'POST',
                        url: urlTest,
                        data: documentToSend,
                        async: false,
                        contentType: 'application/x-www-form-urlencoded',
                        dataType: 'json',
                        success: function (dataResponse) {
                                  numberOfEntriesSuccess++;
                        },
                        error: function (xhr, ajaxOptions, errorThrown) {
                                   var errorResponse = JSON.parse(xhr.responseText);
                                    errorsList.push(errorResponse.ExceptionMessage + ". Skipping line.");
                        }
                    });
    

    【讨论】:

    • 没有。 async: false 1) 不会对问题产生任何影响 2) 难以置信是不好的做法。
    • +1 给罗里。如果您在运行时杀死整个页面,那么 AJAX 的意义何在?如果用户需要在显示数据之前等待某些事情完成,请使用加载光标/图像/...。
    【解决方案4】:

    采用递归方法:

    ajaxLoopArray(myArray, function(){ /* do something when finish */ });
    
    function ajaxLoopArray(someArray, callbackFunction){
        if(someArray.length>0){ //condition to break the loop
            data = someArrapy.pop(); // pop removes the last element from an array and returns that element.
            $.ajax({
                data
            }).done(function(x){
                //success
            })
            .fail(function(){
                //catch the error here
            })
            .always(function(){
                ajaxLoopArray(someArray, callbackFunction); //recursive call: keep on looping independently of success or error
            });
        }else{
            callbackFunction(); //when everything was done
        }
    }
    

    【讨论】:

    • 这将一个一个地发送ajax请求,每次前一个完成时都会发送一个新请求。它会起作用,但与一次发送它们并以它们返回的任何顺序处理它们相比,它不会非常有效。
    猜你喜欢
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多