老實說,寫這篇文章的時候心里是有點壓抑的,因為受到打擊了,為什么?就 因為喜歡折騰不小心看到了這個"簡單"的函數:
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, i * 1000); } console.log(i);什么?這不就是我很久之前看到的先打印一個5,再打印一個5,之后每隔一秒就打印一個5,直到打印完6個5的實現方法嗎?那么問題來了,如果我要依次打印0,1,2,3,4,5的話我該怎么辦,其實在這之前我就知道有這兩個方法:一個是這樣:
function log(i){setTimeout(function(){console.log(i)},i*1000)};for (var i = 0; i < 5; i++) { log(i) ; } console.log(i);還有一個是這樣:
for(var i=0;i<5;i++){(function(e){setTimeout(function(){console.log(e)},i*1000);})(i);};console.log(i);不怕笑話,在這之前我是沒搞懂這兩個函數真正意義上的作用是用來干嘛的,只強迫自己這樣記住這樣修改就可以了,但是現在不行啊,我有強迫癥啊!于是,我慢慢分析了一下,發現上面那段代碼可以分離成這樣:
i=0時;滿足條件;
setTimeout(function(){console.log(i)},0*1000);i=1時;滿足條件;
setTimeout(function(){console.log(i)},1*1000);i=2時;滿足條件;
setTimeout(function(){console.log(i)},2*1000);i=3時;滿足條件;
setTimeout(function(){console.log(i)},3*1000);i=4時;滿足條件;
setTimeout(function(){console.log(i)},4*1000);i=5時,不滿足條件,跳出循環,接著執行for循環后面的console.log(i),打印5;最后依次每秒打印5;
真有意思,為什么setTimeout里面的console.log會是后于for循環外面的console.log執行呢?直到我認識到了這個單詞=>"隊列", 隊列又有宏任務隊列(Macro Task)以及微任務隊列(Micro Task)之分 ,在javascript中:
macro-task包括:script(整體代碼), setTimeout , setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises , Object.observe, MutationObserver
上面函數的setTimeout就屬于宏任務
在js中,事件循環的順序是從script開始第一次循環,隨后全局上下文進入函數調用棧,碰到macro-task就將其交給處理它的模塊處理完之后將回調函數放進macro-task的隊列之中,碰到micro-task也是將其回調函數放進micro-task的隊列之中。直到函數調用棧清空只剩全局執行上下文,然后開始執行所有的micro-task。 當所有可執行的micro-task執行完畢之后。循環再次執行macro-task中的一個任務隊列 ,執行完之后再執行所有的micro-task,就這樣一直循環。
新聞熱點
疑難解答
圖片精選