如何在循环内的ajax异步调用内的循环内更新循环中的进度条

时间:2017-11-15 18:15:07

标签: javascript jquery ajax

我有一个使用kendoGrid的应用程序,我将它们保存到我们的数据库后更新所选行。

有时我们有1000多行,所以我必须对行进行分区,以免使应用程序陷入困境。这需要相当长的时间,所以我想显示一个进度条,以帮助用户查看更新的进度。

问题是进度条在每次迭代中都没有更新。当我逐步使用chrome调试器时,我可以看到进度条更新。但是当我实时运行脚本时没有任何反应。

HTML

<div id="progressbar-wrapper">
    <div id="progressbar-outer" style="display: table;margin: 0 auto;background-color: #FFFFFF;border: 5px solid #000000;width: 50%;height: 30px;opacity: 1;z-index: 9998">
        <div id="progressbar" style="float:left;width: 0;height: 30px;background-color:#000000;border: 0;opacity: 1;z-index: 99999">
        </div>
    </div>
    <div id="loading-animation" style="position: fixed;top: 150px;left: 0;height: 120px;width: 100%;font-size: 100px;line-height: 120px;text-align: center;color: #000000;z-index: 9999;">
        ...SAVING...<br /><small>Saving Lines</small>
    </div>
</div>

JAVASCRIPT

var progressbar = {};
$(function () {

    progressbar = {

        /** initial progress */
        progress: 0,

        /** maximum width of progressbar */
        progress_max: 0,

        /** The inner element of the progressbar (filled box). */
        $progress_bar: $('#progressbar'),

        /** Method to set the progressbar.
         */
        set: function (num) {
            if (this.progress_max && num) {
                this.progress = num / this.progress_max * 100;
                console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max);
                this.$progress_bar.width(String(this.progress) + '%');
            }
        },

        fn_wrap: function (num) {
            setTimeout(function () {
                this.set(num);
            }, 0);
        }

    };

});



var processedPartitions = 0;
var partitions = saveData.partition(30); //saveData is the selected saved rows

//Iterate through partitions
for (var i = 0; i < partitions.length; i++) {

    var urlForWindow = "/Data/Save/";
    $.ajax({
        url: urlForWindow,
        type: "POST",
        dataType: 'json',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify(partitions[i]),
        async: true,
        complete: function () {
            processedPartitions++;
            if (processedPartitions === partitions.length) {

                //PROGRESS BAR (DOESNT WORK, Doesnt show or update the progressbar in real time) ==========================================

                //Get the full number of rows getting updated.
                var iterations = 0;
                for (var i = 0; i < partitions.length; i++) {
                    iterations = iterations + partitions[i].length;
                }

                //add total number of records to update as the iterations
                progressbar.progress_max = iterations;

                //make the progress bar visable before updating //does not show
                $("#progressbar-wrapper").css("display", "block");

                //start counter of rows updated
                var recordsUpdated = 0;

                //begin update loop
                var mainGrid = $("#mainGrid").data("kendoGrid");
                $.each(mainGrid.dataSource.data(), function () {

                    if (this.RowSelected === true) {

                        for (var i = 0; i < partitions.length; i++) {
                            for (var j = 0; j < partitions[i].length; j++) {

                                    var row = mainGrid.dataSource.getByUid(this.uid);
                                    row.set("RowSelected", "false");
                                    row.set("dirty", "false");

                                    //after update iterate recordsupdated
                                    recordsUpdated++;

                                //update the progress bar if not complete //doesnt update in realtime
                                if (iterations >= recordsUpdated) {
                                    progressbar.set(recordsUpdated);        
                                }
                            }
                        }
                    }
                });

                //turn off progressbar after complete // never shows in realtime, never shown closing 
                $("#progressbar-wrapper").css("display", "none");

                //Success message
                alert("Saved");
            }

        },
        error: function (jqXHR, textStatus, errorThrown) {
            alert(jqXHR.resonseText);
        }
    });
}

逐步逐步执行代码,我可以看到一切正常。但是在实时运行时。进度条永远不会显示。就像整个页面冻结一样。

2 个答案:

答案 0 :(得分:0)

由于javascript是单线程的,因此无法同时执行多项任务。然而,HTML5引入了Web工作者,我相信您可以通过Web worker实现您的需求,以便后台线程将用于服务器交互,主线程将为UI更新备用。

Web workers

答案 1 :(得分:0)

所以我想通了。只需将两个过程分开。 ajax完成并将完整标志发送到以下方法以使用事件循环更新网格。

//Get the number of saved data rows. That = total iteration
var iterations = saveData.length; //get data

var processedPartitions = 0;
var partitions = saveData.partition(30); partition data

//write buyer to Database First (Quickest method)
for (var p = 0; p < partitions.length; p++) {
    var urlForWindow = "/Data/Save/";
    $.ajax({
        url: urlForWindow,
        type: "POST",
        dataType: 'json',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify(partitions[p]),
        async: true,
        beforeSend: function () {

        },
        success: function (result) {
            successComplete = 1; //1 means success
        },
        complete: function () {
            processedPartitions++;
            //check if all partitions processed
            if (processedPartitions === partitions.length) {
                successComplete = successComplete + 1; //2 means successful completion
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            alert(jqXHR.resonseText); //0 means error
        }
    });
}


//PROGRESS BAR ================================================
//max progress bar
progressbar.progress_max = iterations;

var mainGrid = $("#mainGrid").data("kendoGrid");

var i = 0; //partition #
var j = 0; //line #
var linesUpdated = 0; //update complete #


//make the progress bar visable before updating
$("#progressbar-wrapper").css("display", "block");


//then loop through update grid methods
(function innerloop() {

    try {
        //If end 
        var testPart = (partitions[i].length - 1); //30 but starts at 0
    } catch (err) {
        //exit loop
        return;
    }

    //Get the length of the partition
    var thisPartitionLength = (partitions[i].length - 1); //30 but starts at 0


    if (thisPartitionLength >= j && successComplete === 2) {

        $.each(mainGrid.dataSource.data(),
            function () {

                if (this.RowSelected === true) { 

                    //get id
                    var row = mainGrid.dataSource.getByUid(this.uid);

                    //unselect and turn off dirty
                    row.set("RowSelected", "false");
                    row.set("dirty", "false");
                    linesUpdated++;
                }
            });
        //update line #
        j++;
        //update progressbar
        progressbar.set(linesUpdated);
    }

    if (j <= thisPartitionLength) {
        //loop if not complete with partition
        setTimeout(innerloop, 0);
    } else {
        if (j > thisPartitionLength) {
            //if end of partition reset the line # and increase partition # and continue loop
            i++;
            j = 0;
            setTimeout(innerloop, 0);
        }

        //on complete
        if (linesUpdated === iterations) {

            //Success message
            alert("Saved");
        }
    }
})();

<强>更新

唉!!这在IE11中不起作用!