當閉包遇上setTimeout

代碼已經過測試。

知識點一:js的事件循環Event Loop

js是單線程執行的。js的執行機制把任務分爲兩類:同步任務、異步任務。

同步任務先執行,執行過程中遇到異步任務,就將其放入任務隊列當中,繼續執行同步任務。同步任務執行完之後,再去檢查任務隊列中要處理的異步任務。

具體的關於Event Loop的內容參考文章:併發模型與事件循環

知識點二: setTimeout

函數setTimeout接受兩個參數:待加入隊列的消息和一個延遲(可選,默認爲 0)。這個延遲代表了消息被實際加入到隊列的最小延遲時間。如果隊列中沒有其它消息,在這段延遲時間過去之後,消息會被馬上處理。但是,如果有其它消息,setTimeout 消息必須等待其它消息處理完。因此第二個參數僅僅表示最少延遲時間,而非確切的等待時間。

接下來開始看具體題目

測試1: 

// 先輸出5
// 然後過3s,一次性輸出5個5
// 先從上到下執行同步代碼,碰到異步的代碼會將其插入到任務隊列當中等待
function test1(){
  for(var i = 0; i < 5; i++){
    setTimeout(function(){
      console.log(i)
    },3000) // 5個setTimeout任務都是等待3s執行,所以3秒一過,大家都輸出。
  }
  console.log(i)
}

 測試2:與1不同在for循環裏有一個閉包,i每次是不同的、獨立的。

// 先輸出5
// 過3s,一次性輸出0 1 2 3 4
// 先從上到下執行同步代碼,碰到異步的代碼會將其插入到任務隊列當中等待
function test2(){
  var j = 1;
  for(var i = 0; i < 5;i ++){
    (function(j){
      setTimeout(function(){
        console.log(j)
      },3000) // 5個setTimeout任務都是等待3s執行,所以3秒一過,大家都輸出。
    })(i)
  }
  console.log('for同步代碼執行之後' + i)
}

測試3:與2不同在延遲時間的設定。i*1000表示後進入隊列任務比它前一任務延遲一秒執行。

// 先輸出5
// 再按時間間隔爲1s輸出0 1 2 3 4
function test3(){
  for(var i = 0; i < 5;i ++){
    (function(){
      setTimeout(function(){
        console.log(i)
      },i*1000) // 與2不同在執行時間間隔上面。後進入隊列都比它前一任務延遲一秒執行。
    })(i)
  }
  console.log('for同步代碼執行之後' + i)
}

測試4:與3不同在,setTimeout的第一參數,因爲是無返回值的閉包,所以第一參數變成了undefined,延時失效。因此會立即執行。

// 立即輸出0 1 2 3 4 | 5
// 因爲setTimeout的一個參數不是function類型,所以setTimeout失效
// 相當於一個for循環內一個單純閉包
// 獨立作用域
function test4(){
  for(var i = 0; i < 5;i ++){
    setTimeout( (function(){
      console.log(i)
    })(i), i*1000) // 與3不同在立即執行函數的位置是在setTimeout內部
  }
  console.log('for同步代碼執行之後' + i)
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章