Javascript 在每个循环中更新progressbar

Javascript 在每个循环中更新progressbar,javascript,jquery,css,progress,Javascript,Jquery,Css,Progress,我有一个进度条,在多次迭代循环中更新 (单击开始按钮前打开控制台) var progressbar={}; $(函数(){ 进度条={ /**初步进展*/ 进展:0, /**进度条的最大宽度*/ 最大进度:0, /**progressbar的内部元素(填充框)*/ $progressbar:$(“#progressbar”), /**设置进度条*/ 设置:函数(num){ if(this.progress\u max&&num){ this.progress=num/this.progress

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

(单击开始按钮前打开控制台)

var progressbar={};
$(函数(){
进度条={
/**初步进展*/
进展:0,
/**进度条的最大宽度*/
最大进度:0,
/**progressbar的内部元素(填充框)*/
$progressbar:$(“#progressbar”),
/**设置进度条*/
设置:函数(num){
if(this.progress\u max&&num){
this.progress=num/this.progress_max*100;
console.log('percent:'+this.progress+'%-'+num+'/'+this.progress_max);
this.$progress_bar.width(字符串(this.progress)+'%');
}
},
fn_wrap:函数(num){
setTimeout(函数(){
此.set(num);
}, 0);
}
};
});
$(“#开始按钮”)。在('单击',函数(){
var迭代次数=100000000;
progressbar.progress_max=迭代次数;
变量循环=函数(){

对于(var i=1;i我猜您的所有进度更新都在同一个调用堆栈中运行。当JavaScript代码运行时,DOM无法更新。也许这将帮助您找到解决方法。

这里是更新的fiddle

我用animate使它成为一个进度条状的外观和感觉。 希望这对你有帮助

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);

                $('#progressbar').animate({
                    width : String(this.progress) + '%',
                }, 500, function() {
                    // Animation complete.
                });
            }
        },

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

});

$('#start_button').on('click', function() {
    $('#progressbar').css('width', '0%');
    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
            }
        }
    }
    loop();
});

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

var i=0;
(函数循环(){
i++;
如果(迭代次数%i==100){
progressbar.set(i);//更新progressbar,即使在循环中也是如此
}   
if(i<迭代次数){
setTimeout(循环,0);
}
})();
我的解决方案:

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

JSFiddle:

一些HTML:

<div class="progress-bar"><div style="width: 0"></div></div>
还有一些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;
});

在继续循环之前,您可以使用
promissions
等待宽度设置完成。
更新100000000次迭代的进度条时,如果按1乘以1,则速度会很慢,因此您可能会发现降低更新频率很有用。
我没有使用
for
循环,而是使用了一个递归函数,在承诺实现时循环

    set: function (num) { 
        var deferred = $.Deferred(); 
        if (this.progress_max && num) {
            this.progress = num / this.progress_max * 100;
            var self = this; 
            self.$progress_bar.animate({"width": String(this.progress) + '%'}, "fast", function() {  
                deferred.resolve(); 
            }); 
            return deferred; 
        }
    }

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

    var iterations = 1000000000;
    var i = 0; 
    progressbar.progress_max = iterations;

    var loop = function(){
        i+=100000000; 
        if(i <= iterations){
            progressbar.set(i).then(function(){ 
                loop(); 
            }); ;         
        }
    }; 

    loop();
});
set:function(num){
var deferred=$.deferred();
if(this.progress\u max&&num){
this.progress=num/this.progress_max*100;
var self=这个;
self.$progress_bar.animate({“width”:String(this.progress)+'%},“fast”,function(){
延迟。解决();
}); 
延期归还;
}
}
$(“#开始按钮”)。在('单击',函数(){
var迭代次数=100000000;
var i=0;
progressbar.progress_max=迭代次数;
var循环=函数(){
i+=100000000;

如果(i让我们将其分解为步骤

步骤1:清理HTML 假设您的问题的目的是了解如何使用进度条,而不是样式或标签(加载、请耐心等待等)。让我们只使用进度条和开始按钮

<div id='progressbar-outer' style="">
    <div id='progressbar' style=""></div>
</div>
<button id="start_button">Start</button>
步骤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);

    }
}
预览
试试这把小提琴:

你必须使用它,否则浏览器将阻塞直到你的循环完成。传递给
requestAnimationFrame
的回调将获得一个时间戳作为参数,你可以使用它来计算进度。

你想做什么?为什么需要它?你应该只使用进度条当你不得不等待某件事情完成时。但我们不知道你在页面上做了什么

  • 如果要显示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;
        }
        ...
    });
    
  • 对于图像,您需要一个ajax调用:

    $.ajax({
        method: "GET",
        url: "http://example.com/path/image.jpg",
        xhr: function() {/* see the code above*/ }
        ...
    });
    
  • 要获取上载文件的内容,请执行以下操作:

    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+"%");
    });
    
  • 对于大范围的流程,如数学或附加大量div,需要10+秒:

    Main.js:

    var worker = new Worker("Worker.js");
    $(worker).bind("message", function(data) {
        $("#progress").width((data*100)+"%");
    });
    
    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);
    

  • 以下是我对这个问题的2点看法:

    使用。webworker blob代码来自

    网络工作者代码:

    <script type="text/ww">    
        function loop(e) {
            var data = JSON.parse(e.data);
            var i = parseInt(data.i, 10);
            var iterations = parseInt(data.iterations, 10);
    
            while (iterations % ++i !== 100 && i <= iterations);
    
            if(i <= iterations) {
                self.postMessage(JSON.stringify({ i: i, iterations: iterations }));
            }
        }
    
        self.onmessage = function(e) {
            loop(e);
        };
    </script>
    
    挂起UI线程,但在视觉上更改宽度,因为我使用requestAnimationFrame中断计数,更改progressbar的宽度,然后继续计数

    function loopFrame(i, iterations) {
        requestAnimationFrame(function() {
            if (iterations % i === 100) {
                progressbar.set(i);
            }
    
            if(i < iterations) {
                loopFrame(i + 1, iterations);
            }
        });
    }
    
    $('#start_button').on('click', function () {
        var iterations = 1000000000;
    
        console.log(iterations);
    
        progressbar.progress_max = iterations;
    
        loopFrame(0, iterations);
    
    });
    
    函数环帧(i,迭代){
    requestAnimationFrame(函数(){
    如果(迭代次数%i==100){
    progressbar.set(i);
    }
    if(i<迭代次数){
    环帧(i+1,迭代);
    }
    });
    }
    $(“#开始按钮”)。在('单击',函数(){
    var迭代次数=100000000;
    console.log(迭代);
    progressbar.progress_max=迭代次数;
    loopFrame(0,迭代次数);
    });
    
    也许这会有用

    var service = new Object();
    
    //function with interrupt for show progress of operations
    service.progressWhile = new Object();
    service.progressWhile.dTime = 50; //step ms between callback display function
    service.progressWhile.i = 0; //index
    service.progressWhile.timer = 0; //start time for cycle
    
    //@parametr arr - array for actions
    //@parametr actionCallback - The function for processing array's elements
    //@parametr progressCallback - function to display the array index
    
    function progressWhile(arr, actionCallback, progressCallback) {
        try {
            var d = new Date();
            service.progressWhile.timer = d.getTime();
            log(service.progressWhile.i);
            if (service.progressWhile.i >= arr.length) {
                service.progressWhile.i = 0;
                return;
            }
    
            while (service.progressWhile.i < arr.length) {
                actionCallback(arr[service.progressWhile.i++]);
                d = new Date();
                if (d.getTime() - service.progressWhile.timer > service.progressWhile.dTime) {
                    break;
                }
            }
            if (progressCallback != undefined)
                progressCallback(service.progressWhile.i);
        } catch (er) {
            log(er);
            return;
        }
    
        setTimeout(function () {
            progressWhile(arr, actionCallback, progressCallback);
        }, 0);
    }
    
    var服务=新对象();
    //具有中断功能,用于显示操作进度
    service.progressWhile=新对象();
    service.progressWhile.dTime=50;//回调显示函数之间的步长ms
    service.progressWhile.i=0;//索引
    service.progressWhile.timer=0;//循环的开始时间
    //@parametr arr-用于操作的数组
    //@Parameterr actionCallback-用于处理数组元素的函数
    //@parametr progressCallback-用于显示数组索引的函数
    函数progressWhile(arr、actionCallback、progressCallback){
    试一试{
    var d=新日期();
    service.progressWhile.timer=d.getTime();
    日志(service.progressWhile.i);
    if(service.progressWhile.i>=arr.length){
    service.progressWhile.i=0;
    返回;
    }
    while(service.progressWhile.i$.ajax({
        method: "GET",
        url: "http://example.com/path/image.jpg",
        xhr: function() {/* see the code above*/ }
        ...
    });
    
    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+"%");
    });
    
    var worker = new Worker("Worker.js");
    $(worker).bind("message", function(data) {
        $("#progress").width((data*100)+"%");
    });
    
    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);
    
    $("#progress").animate({width: "100%"}, 3000);
    
    <script type="text/ww">    
        function loop(e) {
            var data = JSON.parse(e.data);
            var i = parseInt(data.i, 10);
            var iterations = parseInt(data.iterations, 10);
    
            while (iterations % ++i !== 100 && i <= iterations);
    
            if(i <= iterations) {
                self.postMessage(JSON.stringify({ i: i, iterations: iterations }));
            }
        }
    
        self.onmessage = function(e) {
            loop(e);
        };
    </script>
    
    var ww = document.querySelector('script[type="text/ww"]'),
        code = ww.textContent,
        blob = new Blob([code], {type: 'text/javascript'}),
        blobUrl = URL.createObjectURL(blob),
        worker = new Worker(blobUrl);
    
    worker.onmessage = function(e) {
        var data = JSON.parse(e.data);
        var i = parseInt(data.i, 10);
        var iterations = parseInt(data.iterations, 10);
    
        progressbar.set(i);
    
        worker.postMessage(JSON.stringify({ i: i, iterations: iterations }));
    }
    
    $('#start_button').on('click', function () {
    
        var iterations = 1000000000;
    
        progressbar.progress_max = iterations;
    
        worker.postMessage(JSON.stringify({ i: 0, iterations: iterations }));
    });
    
    function loopFrame(i, iterations) {
        requestAnimationFrame(function() {
            if (iterations % i === 100) {
                progressbar.set(i);
            }
    
            if(i < iterations) {
                loopFrame(i + 1, iterations);
            }
        });
    }
    
    $('#start_button').on('click', function () {
        var iterations = 1000000000;
    
        console.log(iterations);
    
        progressbar.progress_max = iterations;
    
        loopFrame(0, iterations);
    
    });
    
    var service = new Object();
    
    //function with interrupt for show progress of operations
    service.progressWhile = new Object();
    service.progressWhile.dTime = 50; //step ms between callback display function
    service.progressWhile.i = 0; //index
    service.progressWhile.timer = 0; //start time for cycle
    
    //@parametr arr - array for actions
    //@parametr actionCallback - The function for processing array's elements
    //@parametr progressCallback - function to display the array index
    
    function progressWhile(arr, actionCallback, progressCallback) {
        try {
            var d = new Date();
            service.progressWhile.timer = d.getTime();
            log(service.progressWhile.i);
            if (service.progressWhile.i >= arr.length) {
                service.progressWhile.i = 0;
                return;
            }
    
            while (service.progressWhile.i < arr.length) {
                actionCallback(arr[service.progressWhile.i++]);
                d = new Date();
                if (d.getTime() - service.progressWhile.timer > service.progressWhile.dTime) {
                    break;
                }
            }
            if (progressCallback != undefined)
                progressCallback(service.progressWhile.i);
        } catch (er) {
            log(er);
            return;
        }
    
        setTimeout(function () {
            progressWhile(arr, actionCallback, progressCallback);
        }, 0);
    }