代碼已經過測試。
知識點一: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)
}