首先請在瀏覽器控制臺執(zhí)行下面的代碼進行測試
setTimeout(function(){console.log("setTimeout執(zhí)行了")},0)
for(var i=0;i<1000000000;i++){
if(i==999999999){
console.log(i);
}
}
如果您的電腦和我的電腦配置差距不太大的話捻撑,就會發(fā)現(xiàn),大約過了三秒后缤底,控制臺才顯示出 999999999顾患,其次才顯示出 “setTimeout執(zhí)行了”。
為什么會出現(xiàn)這樣的情況呢个唧?
這就要從js的執(zhí)行方式說起了江解, 我們知道js是一種單線程,異步的編程語言徙歼。
是因為js支持同步和異步兩種執(zhí)行方式犁河,但是異步執(zhí)行在單線程里的實現(xiàn)方式是作為一個事件對列。
異步執(zhí)行的運行機制如下(參考 JavaScript 運行機制詳解)
(1)所有同步任務都在主線程上執(zhí)行魄梯,形成一個執(zhí)行棧(execution context stack)桨螺。
(2)主線程之外,還存在一個"任務隊列"(task queue)酿秸。只要異步任務有了運行結(jié)果灭翔,就在"任務隊列"之中放置一個事件。
(3)一旦"執(zhí)行棧"中的所有同步任務執(zhí)行完畢辣苏,系統(tǒng)就會讀取"任務隊列"肝箱,看看里面有哪些事件。那些對應的異步任務稀蟋,于是結(jié)束等待狀態(tài)煌张,進入執(zhí)行棧,開始執(zhí)行退客。
(4)主線程不斷重復上面的第三步骏融。
可以知道,只有在同步任務執(zhí)行完畢之后萌狂,任務對列中的異步任務才能進入主線程開始執(zhí)行档玻。
再來看上面的代碼,我故意將循環(huán)次數(shù)設置成一個較大的數(shù)值粥脚,是為了能比較明顯地感受到for循環(huán)(同步任務)的執(zhí)行時間窃肠。
setTimeou中的方法,在for循環(huán)結(jié)束后才執(zhí)行刷允,正是 因為執(zhí)行棧中的同步任務執(zhí)行完之后冤留,任務對列中的任務才能執(zhí)行碧囊,所以導致 “setTimeout執(zhí)行了” 在延遲了接近三秒之后才會執(zhí)行。