更新每个循环中的进度条

reg*_*gie 16 javascript css jquery progress

我有一个进度条,我在许多迭代循环中更新.

https://jsfiddle.net/k29qy0do/32/ (在单击开始按钮之前打开控制台)

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'),

        /** 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);
        }

    };

});


$('#start_button').on('click', function () {

    var iterations = 1000000000;

    progressbar.progress_max = iterations;

    var loop = function () {

        for (var i = 1; i <= iterations; i++) {

            if (iterations % i === 100) {

                progressbar.set(i); //only updates the progressbar in the last iteration

                //progressbar.fn_wrap(i); //even worse, since no output to the console is produced

            }
        }
    }

    //setTimeout(loop, 0);
    loop();

});
Run Code Online (Sandbox Code Playgroud)

控制台按预期迭代更新.但是,进度条未更新.

问题是浏览器窗口似乎"挂起",直到循环结束.仅更新控制台,而不是进度条.

我试图在几个地方添加setTimeout,如下所示.但这只会让事情变得更糟,因为我甚至没有让控制台在执行循环时输出进度.

reg*_*gie 11

好的,我在这个问题的答案中找到了一个解决方案:

Javascript:如何在'for'循环中更新进度条

var i = 0;
(function loop() {
    i++;
    if (iterations % i === 100) {
        progressbar.set(i); //updates the progressbar, even in loop    
    }   
    if (i < iterations) {
        setTimeout(loop, 0);
    }
})();
Run Code Online (Sandbox Code Playgroud)

我的解决方案:https: //jsfiddle.net/ccvs4rer/3/


Gre*_*rdt 7

你真正想要的是一个异步循环,允许浏览器在迭代之间更新DOM.

JSFiddle:http://jsfiddle.net/u5b6gr1w/

function delayedLoop(collection, delay, callback, context) {
    context = context || null;

    var i = 0,
        nextInteration = function() {
            if (i === collection.length) {
                return;
            }

            callback.call(context, collection[i], i);
            i++;
            setTimeout(nextInteration, delay);
        };

    nextInteration();
}
Run Code Online (Sandbox Code Playgroud)

一些HTML:

<div class="progress-bar"><div style="width: 0"></div></div>
Run Code Online (Sandbox Code Playgroud)

一缕CSS:

.progress-bar {
    border: 1px solid black;
    background-color: #f0f0f0;
}
.progress-bar div {
    background-color: red;
    height: 1.25em;
}
Run Code Online (Sandbox Code Playgroud)

还有一些JavaScript将事物连接在一起:

var progressBar = document.querySelector(".progress-bar div"),
    items = [1,2,3,4,5,6,7,8,9,10];

delayedLoop(items, 500, function(item, index) {
    var width = (item / items.length * 100) + "%";
    progressBar.style.width = width;
    progressBar.innerHTML = width;
});
Run Code Online (Sandbox Code Playgroud)


Ada*_*uch 6

我的猜测是所有进度更新都在同一个调用堆栈中运行.当JavaScript代码运行时,DOM无法更新.也许这个问题可以帮助你找到解决方法.


Lor*_*mon 6

让我们把它分解为几步

第1步:清理HTML

假设您的问题的目的是了解如何处理进度条而不是样式或标签(加载,请耐心等).让我们只有进度条和开始按钮.

<div id='progressbar-outer' style="">
    <div id='progressbar' style=""></div>
</div>
<button id="start_button">Start</button>
Run Code Online (Sandbox Code Playgroud)

第2步:样式

让我们让进度条对用户可见

#progressbar-outer {
    height:2em;
    border:5px solid #000;
    width:15em;
}
#progressbar {
    width:0%;
    background-color:#F00;
    height:100%;
}
Run Code Online (Sandbox Code Playgroud)

第3步:使用setTimeout它所属的位置

在您的代码中,您已经习惯setTimeout了设置进度条的值.但是,for循环仍然有效.

for (var i = 1; i <= iterations; i++) {

    if (iterations % i === 100) {

        progressbar.set(i); //only updates the progressbar in the last iteration

        //progressbar.fn_wrap(i); //even worse, since no output to the console is produced

        //setTimeout(function() {
        //  progressbar.set(i);
        //}, 0);

    }
}
Run Code Online (Sandbox Code Playgroud)

使用setTimeout不会影响其余的代码.因此,UI被保留为人质直到循环结束.请尝试以下代码.

$('#start_button').on('click', function () {

    var iterations = 100;

    progressbar.progress_max = iterations;

    var loop = function (value) {
        progressbar.set(value);
        if (value < iterations) setTimeout(function () {
            loop(value + 1)
        }, 30);
        else $('#progressbar').css('background-color', '#0F0');
    }


    loop(1);

});
Run Code Online (Sandbox Code Playgroud)

预习

试试这个小提琴:https://jsfiddle.net/Ljc3b6rn/4/


kle*_*ium 5

你有什么要做的?你为什么需要它?当您必须等待某些事情完成时,您应该只使用进度条.但是我们不知道你在你的页面上做了什么.

  1. 如果要显示ajax上传的进度:

    $.ajax({
        ...
        xhr: function() {
            var xhr = $.ajaxSettings.xhr();
            $(xhr.upload).bind("progress", function(event) {
                var e = event.originalEvent;
                var percent = 0;
                if (e.lengthComputable)
                    percent = Math.ceil(e.loaded/e.total*100);
                $("#progress").width(percent+"%");
            });
            return xhr;
        }
        ...
    });
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于图像,您需要ajax调用:

    $.ajax({
        method: "GET",
        url: "http://example.com/path/image.jpg",
        xhr: function() {/* see the code above*/ }
        ...
    });
    
    Run Code Online (Sandbox Code Playgroud)
  3. 要获取上传文件的内容:

    var reader = new FileReader();
    reader.readAsText(uploadedFile);
    $(reader).bind("progress", function(e) {
        var percent = 0;
        if (e.lengthComputable)
            percent = Math.ceil(e.loaded/e.total*100);
        $("#progress").css("width", percent+"%");
    });
    
    Run Code Online (Sandbox Code Playgroud)
  4. 对于大量的过程,如数学或附加大量的div将需要10+ secons:

    Main.js:

    var worker = new Worker("Worker.js");
    $(worker).bind("message", function(data) {
        $("#progress").width((data*100)+"%");
    });
    
    Run Code Online (Sandbox Code Playgroud)

    Worker.js:

    var total = 43483,
        finished = 0,
        doStuff = function() {
            ++finished;
            return 1+1;
        };
    setInterval(function()
    {
        self.postMessage(finished/total);
    }, 100);
    for (var i = 0; i < total; ++i)
        setTimeout(doStuff, i*10);
    
    Run Code Online (Sandbox Code Playgroud)
  5. 因为它很好,并且你想告诉用户没有进展,只需为div设置动画:

    $("#progress").animate({width: "100%"}, 3000);
    
    Run Code Online (Sandbox Code Playgroud)