對setTimeout函數的理解

以前去面試一家公司時,面試官出了一道關於js的setTimeout函數的題目:javascript

 1 /*
 2 *面試官給的原題目以下:  3 *執行mytest()後,控制檯輸出內容是_____  4 *function mytest() {  5 * for(var i = 0; i < 5; i ++)  6 * setTimeout(console.log(i),0);  7 *}  8 *但這應該不是面試官的問題,當時我也沒有發現問題,回來測試後才發現,這個函數不是  9 *面試官要表達的意思。 10 */
11 //正確的代碼以下:
12 function mytest() { 13     for(var i = 0; i < 5; i ++) 14         setTimeout(function(){ 15  console.log(i); 16         },0); 17 }

個人回答是:控制檯輸出爲5 5 5 5 5,雖然答案對了,可是解釋就太牽強了,我說是由於for語句之執行速度比setTimeout函數快,面試笑了笑,嗚嗚~~(這有毛關係)。
後來網上找了一些資料,參考了一些書籍,這裏我給出一個靠譜的解釋:java

首先,咱們必須認可,js是單線程的,即便是對於ajax異步方式或者像setTimeout這樣的函數。面試

其次,咱們要理解js函數的執行過程,對於setTimeout這樣的函數來講並非每次都能按照預約延遲的時間執行指定函數的。下面舉一個列子:ajax

好比有一個函數fun0在執行開始時建立了一個定時器T1,T1定時器將在200ms後被觸發指定函數。這時咱們須要考慮一個問題,假設fun0的執行時間爲250ms(大於200ms),那將會怎樣?前面已經說過,js是單線程的,因此不存在fun0和定時器同時執行的狀況。這時候定時器制定的函數會在fun0執行完後才執行,定時器的等待時間爲250ms,並非咱們指定的200ms。異步

對於javascript這樣的執行方式,咱們能夠想象在函數執行過程當中有兩個隊列。隊列Q1是指執行隊列,每次只能執行一個函數;隊列Q2就是等待隊列,存放着將要執行的函數。每當有一個函數要執行時,就會先把這個函數放進等待隊列,若是Q1爲空,那麼久當即執行這個函數。固然在大多數狀況下,函數都是當即執行的。函數

所以,咱們能夠知道,setTimeout定時器指定的函數必需要在當前執行隊列爲空時纔會執行。測試

如今咱們再來分析一下上面那道題,很顯然,每次的for循環都觸發了一個定時函數,這些定時函數有點特殊,是當即執行的(若是執行隊列爲空的話)。可是在每次觸發時,for循環都還未結束,也就是執行隊列不爲空,此時新建的定是函數只能放在等待隊列裏沒法當即執行。當最後一次for循環執行結束後,執行隊列變爲空,這時等待隊列的函數就當即進入到了執行隊列,因而就開始執行只控制檯輸出。由於setTimeout指定的匿名函數中i的值是一種引用值(自行谷歌腦補),因此輸出結果爲5 5 5 5 5。spa

如描述或理解有誤,歡迎各位留言!!線程

相關文章
相關標籤/搜索