2017-04-13 52 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>