为什么Progress Bar不会像Text一样动态变化?

我在setTimeout()函数后动态更新了一些元素。 jQuery函数.text()似乎在处理时随着数组索引的每次更改而动态更新。 但是通过.css().attr()更改的bootstrap进度条似乎没有动态更新。 这是我的页面: http : //imdbnator.com/process.php?id = f144caf0843490c0d3674113b03da0c5&redirect = false

您可以看到文本被更改但进度条仅在整个setTimeout()函数完成后才结束。 另外,如果我设置delay = 1000 。 有用。 但它因应用而变慢。 因此,我需要delay = 0 。 但为什么进度条不会改变?

这是我的片段

 function launch(a) { var inc = 0; var maxc = a.length; var delay = 0; // delay milliseconds var iID = setInterval(function () { var index = inc; var movie = a[inc]; //start processing function //styling while processing var markerPer = ((index + 1) / rawListNum) * 100; // marker percentage $("#procNum").text("(" + (index + 1) + "/" + rawListNum + ")"); //Processing number $("#procMovie").text(movie); //Processing Name $("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer); // progress bar -> DOES NOT WORK if (++inc >= maxc) clearInterval(iID); }, delay); } 

通过解释,很多答案都会指出大多数浏览器在UI线程上运行JavaScript的事实,因此在执行JavaScript时它们无法更新界面。 相反,浏览器将等待Javascript完成并将控制权返回给UI线程 。

虽然记住这一点非常重要,但它并没有为您的代码发挥作用。 如果您正在更新进度条,请执行以下操作:

 for (i = 0; i < len; i++) { updateProgressBar(i) }; 

然后它肯定会阻止UI更新直到结束。

但是你已经通过使用setTimeoutsetInterval做了正确的事情,它们在代码中有异步回调。 这意味着JavaScript能够暂停足够长的时间来管理任何UI消息。 事实certificate文本能够动态更新。

正如您的问题所问,为什么,如果UI正在更新,进度条也不会更新?

答案在于Bootstrap将以下CSS应用于进度条 :

 .progress-bar { -webkit-transition: width .6s ease; -o-transition: width .6s ease; transition: width .6s ease; } 

当调用之间的延迟为0ms时,浏览器确实有时间更新UI,但没有时间完成600ms的CSS转换。 因此,直到最后才能看到动画。

正如OhAuth指出的那样 ,您可以通过使用CSS删除过渡效果来阻止浏览器延迟宽度更新:

 .progress .progress-bar { -webkit-transition: none; -o-transition: none; transition: none; } 

如果您循环遍历大量项目,增量更新将提供某种动画。 如果您想留下通用用例的样式,可以在代码中关闭和打开转换。 从jQuery 1.8开始,您可以在没有供应商前缀的情况下更新CSS属性 ,因此您只需要调用.css("transition","none")

当然,根据您为每部电影所做的工作量,JavaScript可以在您可以直观地检测所有UI更改之前完成,在这种情况下延长延迟不会受到影响。 如果您想测试更长时间运行的进程,可以使用以下睡眠function :

 function sleep(sleepyTime) { var start = +new Date; while (+new Date - start < sleepyTime){} } 

这是一个你可以玩的演示,每个设置都是一个变量,你可以配置它来看看它会如何反应,但最好的办法就是有条件地删除过渡。

堆栈片段中的演示

 var delay, numMovies, throttledMovies, sleepTime, removeTransition; $("#delay").change(function(){ delay = this.value }).change() $("#movies").change(function(){ numMovies = this.value }).change() $("#sleep").change(function(){ sleepTime = this.value }).change() $("#transition").change(function(){ removeTransition = this.checked }).change() $("#loadMovies").click(loadMovies); function loadMovies() { var i = 0; throttledMovies = Movies.slice(0, numMovies) if (removeTransition) { $('#progress-bar-movie').css("transition","none"); } var interval = setInterval(function () { loadMovie(i) if (++i >= numMovies) { clearInterval(interval); $('#progress-bar-movie').css("transition","width .6s ease"); } }, delay); }; function loadMovie(i) { var movie = throttledMovies[i]; var percentComplete = ((i + 1) / numMovies) * 100; sleep(sleepTime); // update text $("#procNum").text("(" + (i + 1) + "/" + numMovies + ")"); $("#procMovie").text(movie.Title); // update progress bar $('#progress-bar-movie') .css('width', percentComplete+'%') .attr('aria-valuenow', percentComplete); }; function sleep(sleepyTime) { var start = +new Date; while (+new Date - start < sleepyTime){} } 
             



Current Title:
Progress:

这是由于bootstrap动画在进度条状态中的变化。 如果超时间隔小于动画时间,则会将重绘排队。

尝试将此添加到进度条的CSS:

 -webkit-transition: none; transition: none; 

检查我的小提琴

另一项工作( 参考我以前的答案 ):

如果必须保留动画,则可以使用保守的间隔延迟,例如100毫秒。 用户不应注意的延迟。

如果您确实需要将延迟设置为零以进行计算,那么我将分离计算和进度条值的设置,以便您在一个setInterval中计算值,然后运行单独的setInterval ,每隔100 ms更新一次条形图达到这个价值。

这样您的计算是最新的,您的UI也需要更新时间。

如果你想要他们两个相同的方法,那么我认为你需要添加至少100毫秒的延迟。

示例: https : //jsfiddle.net/dk7g51g4/3/

使用Javascript:

 var _ValueToSet = 0; $(document).ready(function () { // SET VALUE EXTREMELY FAST (your current code) setInterval(function () { _ValueToSet = Math.round(Math.random() * 100); // get value we are going to set } , 0); // run as fast as possible // RUN UI UPDATE AT 100MS (separate thread for ui updates). setInterval(function () { setRandom() } , 100); // give ui 100ms to do its thing }); function setRandom() { var elem = $('.progress-bar'); // what is our target progress bar // set both style width and aria-valuenow elem.css('width', _ValueToSet + '%'); elem.attr('aria-valuenow', _ValueToSet); } 

HTML:

 

这可能是一个重绘问题。 由于延迟设置为0,因此在上次更新之前不会绘制CSS更改。

强制重绘的最简单方法是读取元素高度:

 $("div[role='progressbar']").css("width", markerPer + "%").attr("aria-valuenow", markerPer); $("div[role='progressbar']").height(); 

文本和进度条动态更改,但delay === 0 ,速度非常快:( http://jsfiddle.net/sergdenisov/mh4o1wxz/1/ ):

HTML:

 
Text

使用Javascript:

 var delay = 0; var percent = 0; var iID = setInterval(function() { percent += 10; $('.text').text('Text ' + percent + '/100'); $('.progress-bar').css('width', percent + '%').attr('aria-valuenow', percent); if (percent === 100) { clearInterval(iID); } }, delay);