js設計爲單線程仍是跟他的用途有關
試想一下 若是js設計爲多線程 那麼同時修改和刪除同一個dom 瀏覽器又該如何執行?
for (var i=0;i<9999;i++){ console.log("我在執行 但用戶不知道") } console.log("你好啊")
上圖例子 for循環耗時會好久
這意味着 用戶得不到 '你好啊' 的響應 就會下意識會認爲瀏覽器卡死了 因此js必需要有異步
js經過事件循環來實現異步 這也是js的運行機制
遇到同步任務直接執行,遇到異步任務分類爲宏任務(macro-task)
和微任務(micro-task)
。
宏任務:總體的Script
setTimeout
setInterval
微任務:Promise
process.nextTick
請看示例代碼:javascript
// 這是一個同步任務 console.log('1') --------> 直接被執行 目前打印結果爲:1 // 這是一個宏任務 setTimeout(function () { --------> 總體的setTimeout被放進宏任務列表 console.log('2') 目前宏任務列表記爲【s2】 }); new Promise(function (resolve) { // 這裏是同步任務 console.log('3'); --------> 直接被執行 resolve(); 目前打印結果爲:一、3 // then是一個微任務 }).then(function () { --------> 總體的then[包含裏面的setTimeout]被放進微任務列表 console.log('4') 目前微任務列表記爲【t45】 setTimeout(function () { console.log('5') }); });
第一輪小結: 執行到這裏的結果:一、3 宏任務列表以下: setTimeout(function () { console.log('2') }); 微任務列表以下: then(function () { console.log('4') setTimeout(function () { console.log('5') }); });
若是微任務列表裏面有任務 會執行完畢後在執行宏任務 (ps:開篇有流程圖)
瀏覽器瞅了一眼微任務列表 發現裏面有微任務 就開始所有執行 then(function () { console.log('4') --------> 直接被執行 目前打印結果爲:一、三、4 setTimeout(function () { --------> 被放進宏任務列表了 console.log('5') 目前宏任務列表記爲【s二、s5】 }); }); 瀏覽器發現微任務執行完畢了 開始執行宏任務列表 setTimeout(function () { console.log('2') --------> 直接被執行 目前打印結果爲:一、三、四、2 }); setTimeout(function () { console.log('5') --------> 直接被執行 目前打印順序爲: 一、三、四、二、五、5 }); 最終結果爲: 一、三、四、二、5
反覆執行以上步驟 就是事件循環(event loop)
必定要分的清任務類型 (宏任務 和 微任務)
TIP: 爲了容易辨別起名爲p1(p開頭 裏面打印1) process.nextTick(function() { --------> 被放微任務列表 console.log('1'); 微任務列表記爲:【p1】 }) new Promise(function (resolve) { console.log('2'); --------> 直接執行 resolve(); 目前打印順序爲:2 }).then(function () { --------> 總體的then被放進微任務列表[包含其中的setTimeout 4] console.log('3'); 微任務列表記爲:【p1 t34】 setTimeout(function () { console.log('4') }); }); setTimeout(function () { --------> 被放宏任務列表 console.log('5') 宏任務列表記爲:【s5】 }); new Promise(function (resolve) { setTimeout(function () { --------> 被放宏任務列表 console.log('6') 宏任務列表記爲:【s5 s6】 }); resolve() }).then(function () { --------> 總體的then被放進微任務列表[包含其中的setTimeout和其中的多層嵌套] setTimeout(function () { 微任務列表記爲:【p1 t34 t789】 console.log('7') new Promise(function (resolve) { setTimeout(function () { console.log('8') }); resolve() }).then(function () { setTimeout(function () { console.log('9') }); }); }); }); console.log('10') --------> 直接執行 目前打印順序爲:二、10
第一輪小結: 執行結果爲:二、10 宏任務列表以下: // s5 setTimeout(function () { console.log('5') }); //s6 setTimeout(function () { console.log('6') }); 微任務列表以下: // p1 process.nextTick(function() { console.log('1'); }) // t34 then(function () { console.log('3'); setTimeout(function () { console.log('4') }); }); // t789 then(function () { setTimeout(function () { console.log('7') new Promise(function (resolve) { setTimeout(function () { console.log('8') }); resolve() }).then(function () { setTimeout(function () { console.log('9') }); }); });
開始執行第二輪: 有微任務 先執行微任務 將微任務列表代碼塊搬下來 // p1 process.nextTick(function() { --------> 執行p1 console.log('1'); 目前打印順序爲:二、十、1 }) // t34 then(function () { console.log('3'); --------> 直接執行 目前打印順序爲:二、十、一、3 setTimeout(function () { --------> 被放宏任務列表 console.log('4') 宏任務列表記爲:【s5 s6 s4】 }); }); // t789 then(function () { setTimeout(function () { --------> 被放宏任務列表 console.log('7') 宏任務列表記爲:【s5 s6 s4 s789】 new Promise(function (resolve) { setTimeout(function () { console.log('8') }); resolve() }).then(function () { setTimeout(function () { console.log('9') }); }); }); }) 微任務執行完畢了 該執行咱們的宏任務列表了 由於微任務裏面包含一部分宏任務 因此如今的宏任務列表已經增長了 如今把當前的宏任務列表搬下來 //s5 setTimeout(function () { --------> 執行s5 console.log('5') 目前打印順序爲:二、十、一、三、5 }); //s6 setTimeout(function () { --------> 執行s6 console.log('6') 目前打印順序爲:二、十、一、三、五、6 }); //s4 setTimeout(function () { --------> 執行s4 console.log('4') 目前打印順序爲:二、十、一、三、五、六、4 }); // s789 setTimeout(function () { --------> 執行s789 console.log('7') 目前打印順序爲:二、十、一、三、五、六、四、7 new Promise(function (resolve) { setTimeout(function () { --------> 被放宏任務列表 console.log('8') 宏任務列表記爲:【s8】 }); resolve() }).then(function () { --------> 總體的then被放微任務列表[包含裏面的setTimeout] setTimeout(function () { 微任務列表記爲:【t9】 console.log('9') }); }); });
再次小結: 當前結果:二、十、一、三、五、六、四、7 立刻就要執行完了內心萬分激動啊 ( 瀏覽器的心裏獨白 ^▽^ ...) 宏任務列表以下: // s8 setTimeout(function () { console.log('8') }); 微任務列表以下: // t9 then(function () { setTimeout(function () { console.log('9') }); }); 繼續執行 依舊遵循有微則微 無微則宏 瀏覽器發現有一條微任務 那就開始執行吧~ //t9 then(function () { setTimeout(function () { --------> 執行t9 把裏面的setTimeout放入宏任務列表 console.log('9') 宏任務列表記爲:【s8 s9】 }); }); 微任務列表執行完畢 開始執行宏任務(宏任務剛剛又有新增哦~[s9]) // s8 setTimeout(function () { --------> 執行s8 console.log('8') 目前打印順序爲:二、十、一、三、五、六、四、七、8 }); // s9 setTimeout(function () { --------> 執行s9 console.log('9') 目前打印順序爲:二、十、一、三、五、六、四、七、八、9 }); 到這裏 微任務列表 和 宏任務列表均爲空 就執行完畢了
再此留下一道沒有答案的題供練手java
new Promise(function (resolve) { console.log('1'); resolve(); }).then(function () { setTimeout(function () { console.log('2') }); }); setTimeout(function () { console.log('3') process.nextTick(function() { console.log('4'); }) process.nextTick(function() { console.log('5'); }) }); new Promise(function (resolve) { console.log('6'); resolve(); setTimeout(function () { console.log('7') new Promise(function (resolve) { console.log('8'); resolve(); }).then(function () { setTimeout(function () { console.log('9') }); }); }); }).then(function () { setTimeout(function () { console.log('10') }); new Promise(function (resolve) { console.log('11'); resolve(); }).then(function () { setTimeout(function () { console.log('12') }); }); });
本人學識有限 文章多有不足 如有錯誤 請大方指出 以避免誤導他人