setTimeout的實現原理以及setTimeout(0)的使用場景

 

先看一段代碼:javascript

[javascript]  view plain  copy
 
  1. var start = new Date();  
  2. setTimeout(function(){  
  3.     var end = new Date();  
  4.     console.log("Time elapsed: ", end - start, "ms");  
  5. }, 500);  
  6.   
  7. while (new Date - start <= 1000)  
  8. {  
  9.   
  10. }  

運行這段腳本能夠看到:Time elapsed的值大概在1001ms左右,確定會超過1000ms。也就是說:setTimeout失效了,指定的函數並無在500ms後執行,而是延遲到1000ms後才執行。html

 

再看一段代碼:java

 

[javascript]  view plain  copy
 
  1. function a()  
  2. {  
  3.     setTimeout(function(){console.log(1);},0);  
  4.     console.log(2);  
  5. }  
  6. a();  

 

運行這段腳本能夠看到:先打印2後打印1,咱們在setTimeout裏面指定了0ms,但願能當即執行,可是實際上沒有效果。瀏覽器

 

想要理解上面的2段代碼,咱們得了解一下JavaScript中setTimeout的實現原理。首先牢記一點:JavaScript 是單線程執行的,也就是沒法同時執行多段代碼。下面這段解釋來自這篇博客異步

        JavaScript是單線程執行的,沒法同時執行多段代碼。當某一段代碼正在執行的時候,全部後續的任務都必須等待,造成一個隊列。一旦當前任務執行完畢,再從隊列中取出下一個任務,這也常被稱爲 「阻塞式執行」。因此一次鼠標點擊,或是計時器到達時間點,或是Ajax請求完成觸發了回調函數,這些事件處理程序或回調函數都不會當即運行,而是當即排隊,一旦線程有空閒就執行。假如當前 JavaScript線程正在執行一段很耗時的代碼,此時發生了一次鼠標點擊,那麼事件處理程序就被阻塞,用戶也沒法當即看到反饋,事件處理程序會被放入任務隊列,直到前面的代碼結束之後纔會開始執行。若是代碼中設定了一個 setTimeout,那麼瀏覽器便會在合適的時間,將代碼插入任務隊列,若是這個時間設爲 0,就表明當即插入隊列,但不是當即執行,仍然要等待前面代碼執行完畢。因此 setTimeout 並不能保證執行的時間,是否及時執行取決於 JavaScript 線程是擁擠仍是空閒。函數

 

也就是說setTimeout只能保證在指定的時間事後將任務(須要執行的函數)插入隊列等候,並不保證這個任務在何時執行。執行javascript的線程會在空閒的時候,自行從隊列中取出任務而後執行它。javascript經過這種隊列機制,給咱們製造一個異步執行的假象。this

 

[javascript]  view plain  copy
 
  1. var start = new Date();  
  2. setTimeout(function(){  
  3.     var end = new Date();  
  4.     console.log("Time elapsed: ", end - start, "ms");  
  5. }, 500);  
  6.   
  7. console.log("task finished.");  
咱們之因此會感受到這段代碼是在異步執行,這是由於javascript線程並無由於什麼耗時操做而阻塞,因此能夠很快地取出排隊隊列中的任務而後執行它。

 

如今咱們知道了setTimeout的原理了,如今看下setTimeout(0)的使用場景。下面這個例子來自這篇文章spa

 

[html]  view plain  copy
 
  1. <input type="text" onkeydown="show(this.value)">  
  2. <div></div>  
  3. <script type="text/javascript">  
  4.   function show(val) {  
  5.     document.getElementsByTagName('div')[0].innerHTML = val;  
  6.   }  
  7. </script>  
這裏綁定了 keydown 事件,意圖是當用戶在文本框裏輸入字符時,將輸入的內容實時地在 <div> 中顯示出來。可是實際效果並不是如此,能夠發現,每按下一個字符時,<div> 中只能顯示出以前的內容,沒法獲得當前的字符。

 

 

[html]  view plain  copy
 
  1. <input type="text" onkeydown="var self=this; setTimeout(function() {show(self.value)}, 0)">  
  2. <div></div>  
  3. <script type="text/javascript">  
  4.   function show(val) {  
  5.     document.getElementsByTagName('div')[0].innerHTML = val;  
  6.   }  
  7. </script>  

這段代碼使用了setTimeout(0)就能夠實現須要的效果了。這裏其實涉及2個任務,1個是將鍵盤輸入的字符回寫到輸入框中,一個是獲取文本框的值將其寫入div中。第一個是瀏覽器自身的默認行爲,一個是咱們本身編寫的代碼。很顯然,必需要先讓瀏覽器將字符回寫到文本框,而後咱們才能獲取其內容寫到div中,若是當即執行獲取文本框的值,其實輸入框尚未輸入的內容。改變順序,這這正是setTimeout(0)的做用。.net

 原文連接:http://blog.csdn.net/aitangyong/article/details/46800615線程

 

儘管setTimeout的delay是0,也會做爲一次異步調用,而每次異步調用結束後都會render頁面

相關文章
相關標籤/搜索