setTimeout和setInterval這兩個函數, 你們確定都不陌生, 但可能並非每一個人都瞭解其內部的實質。javascript
甚至可能會錯誤的把兩個實現定時調用的函數理解成了相似thread同樣的東西, 認爲會在一個時間片內, 併發的執行調用的函數, 彷佛很好很強大。但其實並非如此, 實際的狀況是javascript都是以單線程的方式運行於瀏覽器的javascript引擎中的。java
setTimeout和setInterval的做用只是把你要執行的代碼在你設定的一個時間點插入js引擎維護的一個代碼隊列中, 插入代碼隊列並不意味着你的代碼就會立馬執行的,理解這一點很重要. 並且setTimeout和setInterval還有點不同。瀏覽器
function click() { // code block1... setTimeout(function() { // process ... }, 200); // code block2 }
假設咱們給一個button的onclick事件綁定了此方法。併發
當咱們按下按鈕後, 確定先執行block1的內容, 而後運行到setTimeout的地方, setTimeout會告訴瀏覽器說: "200ms後我會插一段要執行的代碼給你的隊列中", 瀏覽器固然答應了(注意插入代碼並不意味着立馬執行), setTimeout代碼運行後, 緊跟其後的block2代碼開始執行。函數
這裏就開始說明問題了, 若是block2的代碼執行時間超過200ms, 那結果會是如何? 或許按照你以前的理解, 會理所固然的認爲200ms一到, 你的process代碼會立馬執行...事實是, 在block2執行過程當中(執行了200ms後)process代碼被插入代碼隊列, 但一直要等click方法執行結束, 纔會執行process代碼段, 從代碼隊列上看process代碼是在click後面的, 再加上js以單線程方式執行, 因此應該不難理解. 若是是另外一種狀況, block2代碼執行的時間<200ms, setTimeout在200ms後將process代碼插入到代碼隊列, 而那時執行線程可能已經處於空閒狀態了(idle), 那結果就是200ms後, process代碼插入隊列就立馬執行了, 就讓你感受200ms後, 就執行了。spa
這裏可能會存在兩個問題:
1.時間間隔或許會跳過
2.時間間隔可能小於定時調用的代碼的執行時間線程
function click() {
// code block1... setInterval(function() { // process ... }, 200); // code block2 }
和上面同樣咱們假設經過一個click, 觸發了setInterval以實現每隔一個時間段執行process代碼code
好比:onclick要300ms執行完, block1代碼執行完, 在5ms時執行setInterval, 以此爲一個時間點, 在205ms時插入process代碼, click代碼順利結束, process代碼開始執行(至關於圖中的timer code), 然而process代碼也執行了一個比較長的時間, 超過了接下來一個插入時間點405ms, 這樣代碼隊列後又插入了一份process代碼, process繼續執行着, 並且超過了605ms這個插入時間點。blog
下面問題來了, 可能你還會認爲代碼隊列後面又會繼續插入一份process代碼...... 真實的狀況是,因爲代碼隊列中已經有了一份未執行的process代碼, 因此605ms這個插入時間點將會被"無情"的跳過, 由於js引擎只容許有一份未執行的process代碼, 說到這裏不知道您是否是會豁然開朗呢...隊列
爲了解決這種問題你能夠用一種更好的代碼形式:
setTimeout(function(){ //processing setTimeout(arguments.callee, interval); }, interval);
這個估計稍微想一下, 就明白其中的好處了, 這樣就不會產生時間點被跳過的問題了。