做爲入門者來講,瞭解JavaScript中timer的工做方式是很重要的。一般它們的表現行爲並非那麼地直觀,這是由於它們都處在單線程中。讓咱們先來看看三個用來出建立和操做timer的函數。javascript
var id = setTimeout(fn, delay);
初始化這個timer,而後這個timer將會在delay延時後調用這個函數fn。這個函數將返回一個惟一的ID,能夠經過這個ID來取消timer。java
var id = setInterval(fn, delay);
與setTimeout相似,不過它會持續調用函數fn(每隔delay毫秒),直到timer被取消。
瀏覽器
clearTimeout(id); clertInterval(id);
接受一個timer的ID,並中止timer的回調事件。
異步
爲了理解timer內部工做原理,咱們還須要知道一個重要的概念:timer的延時是不許確的。因爲瀏覽器中的JavaScript在單線程中運行,所以異步事件(如mouse click以及timer)只有在執行期空閒的時候才運行。這個用圖表最能解釋清楚了,參看下圖:
函數
這個圖標中有大量的信息能夠挖掘,可是徹底理解它將使咱們對JavaScript中異步事件執行原理有個更深的認識。這是一張一維圖:數值方向爲時間,單位毫秒。藍色的框表示正在執行的JavaScript片斷。舉個例子,第一塊JavaScript大約執行了18ms,鼠標點擊則執行了11ms,以此類推。
spa
因爲JavaScript在同一時間只能執行一段代碼(由單線程的本質決定),所以每一個代碼塊都會「阻塞」其餘異步事件。這意味着當異步事件發生時(好比鼠標點擊、timer觸發或者XMLHttpRequest完成),將進入事件隊列等待執行(隊列的實現方式因瀏覽器而異,這裏只討論簡化的狀況)。
線程
從第一段JavaScript代碼塊開始,有兩個timer被初始化了:一個10ms的setTimeout和一個10ms的setInterval。其實在第一段代碼塊執行完以前timer就已經觸發了。注意,不管如何它都不會當即執行(因爲單線程緣由,它沒法那樣作)。相反,這個延時執行的函數進入隊列等待下次空閒的時候執行。
code
此外,第一段代碼塊中鼠標點擊事件也發生了。所以和異步事件相關聯的回調函數也不能當即執行,像最初的timer同樣,也要進入隊列等待執行。
blog
最初的代碼塊執行完之後,瀏覽器問了這樣一個問題:誰在等待執行?這個例子中,鼠標點擊事件和timer回調函數都處於等待中。瀏覽器挑了鼠標點擊事件,而後當即執行它。而timer將繼續等待下次執行。
隊列
注意當鼠標點擊事件執行過程當中時,第一次的interval的回調也觸發了。和timer同樣,它的事件也將進入隊列等待執行。而後,當interval再次觸發的時候(此時timer正在執行),此次它的事件將被丟棄。若是你在一大塊代碼執行時,把全部的interval的回調事件排入隊列,其結果是在上述代碼執行完之後,一推的interval事件將毫無間隔地執行。而瀏覽器更趨向於等待,以確保interval事件進入隊列時沒有其餘的interval事件。
事實上,從這個例子中能夠看出:當第三個interval觸發的時候,interval自身正在執行。這告訴咱們一個重要的事實:interval無論當前執行的是什麼,都會進入隊列,即便這樣意味着回調函數之間的時間就不許確了。
最後,當第二個interval事件執行完之後,將沒有任何代碼留給JavaScript引擎執行。這意味着如今瀏覽器將等待新的異步事件觸發。因而在50ms的時候,interval再一次觸發。這一次,沒有什麼阻塞它的執行,它就當即觸發了。
讓咱們看一個例子來更好的闡述setTimeout和setInterval之間的區別。
setTimeout(function(){ /*Some long block of code */ setTimeout(argument.callee, 10) }, 10); setInterval(function(){ /*Some long block of code */ }, 10)
咋看一下,這兩段代碼的功能彷佛是同樣的,但實際上並不是如此。尤爲是setTimeout這段代碼,在前一個回調函數執行完之後,都至少會有10ms的延時(可能會多,但毫不會少)。然而,setInterval的代碼則老是每10ms的時候嘗試執行回調,不管上一次回調何時執行的。
重述下學到的知識。
JavaScript引擎只有一個線程,這使得異步事件必須排入隊列等待執行
setTimeout和setInterval在執行異步代碼上有着本質的區別
若是timer在將要執行的時候被阻塞,它將等待下一個時機
若是interval執行的時候很長(比指定的時間長),那麼它們將連續地執行而沒有延時。
原文:jQuery之父John Resig的Blog