2017-04-13 48 views
1

我有一个非常简单的HTML/Javascript如下 但是当我运行它时,标签只更新一次,当它是99999时,这不是我的预期行为。我希望标签在“实时”更新。有什么办法可以强制它重绘。我试图把它变成一个javascript div更新率

notice.style.display = 'none'; 
notice.innerHTML = i 
notice.style.display = 'block'; 

但它仍然无法正常工作。 非常感谢。

<html> 
    <head> 
    </head> 
    <body> 
    <label id = "esperanto-notice"></label> 
    <script type="text/javascript"> 
     var notice = document.getElementById("esperanto-notice") 
     for(var i =0; i<100000; i++){ 
     notice.innerHTML = i 
     console.log(i) 
     } 
     console.log("done") 
    </script> 
    </body> 
</html> 

回答

2

JavaScript尝试更新DOM之前运行的所有内嵌代码,因为后者是缓慢的。整个循环在页面更新一次之前运行。

我们可以强制页面更新:

for(var i =0; i<100000; i++){ 
    notice.innerHTML = i; 
    notice.getBoundingClientRect(); // Force DOM update to get latest size 
    console.log(i); 
} 

然而,当DOM被更新它仍然径直回到JS继续运行循环 - 这是更新的速度比你可以看到和仍然似乎挂起。

你需要做的是暂停JS执行,以便页面有机会更新

我们可以异步JS功能做到这一点 - 这是结束当前JS块但排队的回调函数后火(在这种情况下,用户看到后话):

var notice = document.getElementById("esperanto-notice"); 
 
var i = 0; 
 

 
// Function to write the next value, increment, and queue up the next timeout 
 
var nextFunc = function() { 
 
    console.log(i); 
 
    notice.innerHTML = i++; 
 
    if (i < 100000) 
 
    setTimeout(nextFunc, 16); // 16ms is 60FPS 
 
    else 
 
    console.log('done'); 
 
} 
 

 
// Start it off 
 
nextFunc();
<label id="esperanto-notice"></label>

现在整个JS运行并且nextFunc执行一次。它也会在16ms后将它排队等待再次启动,但在此之前它会让浏览器更新页面。

每次nextFunc都会触发它使用setTimeout来排队下一次执行,然后页面有一帧要更新(所以用户看到它),然后它再次触发。

现代浏览器提供的功能尤其是等待下一帧:requestAnimationFrame

var notice = document.getElementById("esperanto-notice"); 
 
var i = 0; 
 

 
// Function to write the next value, increment, and queue up the next timeout 
 
var nextFunc = function() { 
 
    console.log(i); 
 
    notice.innerHTML = i++; 
 
    if (i < 100000) 
 
    // Request the next visible frame to continue 
 
    requestAnimationFrame(nextFunc); 
 
    else 
 
    console.log('done'); 
 
} 
 

 
// Start it off 
 
nextFunc();
<label id="esperanto-notice"></label>

这是最好的办法,除非你需要支持IE浏览器的旧版本(< = 9 ),因为​​可以处理任何帧的持续时间(如果你有很多的麻烦,则可以有setTimeout问题)。

最后,这是新的语言关键字asyncawait可以使您的代码更容易。您可以保持循环并抽象等待DOM更新。接下来的这个片段只能运行在现代浏览器Chrome和FX(但可以使用巴贝尔或打字稿支持IE):

(async function() { 
 
    var notice = document.getElementById("esperanto-notice"); 
 
    for (var i = 0; i < 100000; i++) { 
 
    console.log(i); 
 
    notice.innerHTML = i; 
 
    
 
    // Pass back to the DOM until the next frame 
 
    await new Promise(r => requestAnimationFrame(r)); 
 
    } 
 

 
    console.log('done'); 
 
})();
<label id="esperanto-notice"></label>

+1

哇。这是一个非常全面的答案。它非常适合我的需求。非常感谢你! – user3649135

2

您的循环运行速度非常快,您无法实时看到变化。为了达到你的目标,你应该在增量计数器前做一些超时。例如:

<html> 
 
    <head> 
 
    </head> 
 
    <body> 
 
    <label id = "esperanto-notice"></label> 
 
    <script type="text/javascript"> 
 
     var notice = document.getElementById("esperanto-notice") 
 
     var i = 0; 
 
     var interval = setInterval(function() { 
 
     notice.innerHTML = ++i; 
 
     if (i === 100000) 
 
      clearInterval(interval) 
 
     }, 500); 
 
    </script> 
 
    </body> 
 
</html>

0

基本上更新发生的相当快,你只能看到最后的更新在该专区,

尝试改变for循环到下面看到的变化

for(var i =0; i<100000; i++) 
    { 
    (function(i){ //wrapping the value of i in an IIFE so that it can be locked 
     setTimeout(function(){ 
     notice.innerHTML = i 
     console.log(i) 
     } , i * 100); //i*100 is in milliseconds   
    })(i); 
    } 
0

使用javascript setIntervalclearinterval

<html> 
 
<body> 
 
    <label id="esperanto-notice"></label> 
 
    <script type="text/javascript"> 
 
     var notice = document.getElementById("esperanto-notice"); 
 
     var i = 0; 
 
     var interval = setInterval(function() { 
 
      notice.innerHTML = i; 
 
      i++; 
 
      if(i >= 100000) { 
 
       clearInterval(interval); 
 
      } 
 
     }, 100); 
 
     
 
     
 
    </script> 
 
</body> 
 

 
</html>

0

for循环执行milliseconds,你只能得到你的循环的最后一个值。如果你想在实时只使用setInterval

var notice = document.getElementById("esperanto-notice") 
 
var i = 0 
 
var refreshIntervalId = setInterval(changeCounter,1000) 
 
function changeCounter(){ 
 
    i++ 
 
    notice.innerHTML = i 
 
    if(i==10){ 
 
    clearInterval(refreshIntervalId) 
 
    console.log("done") 
 
    } 
 
}
<html> 
 
    <body> 
 
    <label id = "esperanto-notice"></label> 
 
    </body> 
 
</html>

0

由于你的代码是在“实时”的运行速度非常快其实你无法看到数字改变你的屏幕上。为了做到这一点,你需要这些数字慢慢变化,以便你注意到。为此,您可以设置Timeout并将更新延迟到DOM。

var notice = document.getElementById("esperanto-notice") 
 
    for (var i = 0; i < 100000; i++) { 
 
     setTimeout(function(innerI) { 
 
      notice.innerHTML = innerI; 
 
      console.log(innerI); 
 
     }.bind(null, i), i * 100); 
 
    } 
 
    console.log("done")
<html> 
 
<head> 
 
</head> 
 
<body> 
 
    <label id="esperanto-notice"></label> 
 
    
 
</body> 
 
</html>