JavaScript中的Event Loop小理解

Event Loop

Event Loop定義了瀏覽器執行你寫的代碼的順序。我們都知道瀏覽器在執行代碼的時候,並不一定按照你寫的順序來執行,因爲這裏邊可能存在異步執行,而且可能有多個異步代碼,還有可能有多種異步代碼。那麼當這種情況存在的時候,瀏覽器就需要有一種機制,來判斷當前應當執行哪部分代碼。
然後,還需要知道Event Loop機制中兩個任務,第一個是宏任務MacroTask,第二個是微任務MicroTask,還有一個叫執行棧的東西。Event Loop的機制就是先讓執行棧執行完宏任務隊列中的所有任務,然後再執行微任務隊列中的所有任務,完了繼續循環。

  • 執行棧:所有的js代碼都會被放到執行棧中依次執行。
  • 宏任務:簡單點說,就是一串js代碼,但是被劃分爲了宏任務。哪些會被劃分爲宏任務呢?包括script標籤中代碼 setTimeout setInterval I/O UI渲染 postMessage等(並沒有歸納完)。宏任務可以繼續產生宏任務/微任務。
  • 微任務:同理,也是一串被劃分爲微任務的js代碼。包括Promise中的resolve/reject async/await process.nextTick等(並沒有歸納完)。同樣,微任務也可以繼續產生宏任務/微任務。
    廢話少說,趕緊聚個例子:
//先來個簡單點的
console.log("start");
setTimeout(_ => console.log("setTimeout"), 0);
console.log("end");
// start
// end
// setTimout
//解釋不?算了不解釋了
// 第二個例子,還是簡單點
console.log("start");
setTimeout(_ => console.log("setTimeout"), 0);
new Promise(resolve => {
  console.log("new Promise");
  resolve("promise then");
}).then(res => console.log(res));
console.log("end");
// start
// new Promise
// end
//promise then
// setTimeout
//解釋不?還是解釋哈嘛……
/* 是弄個子的
1.執行棧會首先去拿宏任務列表中的代碼塊來執行,此時只有script標籤代碼,所以就拿過來執行咯喲
2.執行第一句,輸出 start
3.執行第二句,遇到了setTimeout,此時會將其回掉任務加入到下一輪的宏任務中
4.new Promise中的代碼直接執行(爲什麼直接執行,請看Promise相關知識),
輸出 new Promise,完了遇到了resolve代碼,此時會將其回掉任務加入到下一輪微任務中
5.輸出 end,此時,本輪宏任務執行完畢,開始執行微任務
6.由上可知,微任務中第一條(也僅此一條)是resolve的回掉,所以拿出來執行,輸出 promise then
7.微任務執行完了,再次執行宏任務,也從第一條開始,輸出setTimeout
8.done!!!
*/
//第三個例子,不難,只是多增加了兩位新客人而已
console.log("start");
setTimeout(_ => console.log("setTimeout"), 0);
new Promise(resolve => {
  console.log("new Promise");
  setTimeout(_ => console.log("new Promise setTimeout"), 0);
  resolve("promise then");
}).then(res => console.log(res));
async function asyncFunc1() {
  console.log("asyncFunc1 start");
  await asyncFunc2();
  console.log("asyncFunc1 end");
}
async function asyncFunc2() {
  console.log("asyncFunc2");
}
asyncFunc1();
console.log("end");
/* 先補充哈async/await的只是哈 */ /* 開始補充... */ /* 補充完畢 */
//輸出
//start
//new Promise
//asyncFunc1 start
//asyncFunc2
//end
//promise then
//asyncFunc1 end
//setTimeout
//new Promise setTimeout
/* 不用解釋了,只要曉得 async/await 而且李傑了上一個例子,那就沒問題了 */
// 第四個例子
console.log("start");
setTimeout(function setTimeoutCallbackFunc1() {console.log("setTimeout")}, 0);
new Promise(resolve => {
  console.log("new Promise");
  setTimeout(function setTimeoutCallbackFunc2() {console.log("new Promise setTimeout")}, 0);
  resolve("promise then");
}).then(function promiseThenCallbackFunc1(res) {console.log(res)});
async function asyncFunc1() {
  console.log("asyncFunc1 start");
  await asyncFunc2();
  console.log("asyncFunc1 end");
}
async function asyncFunc2() {
  console.log("asyncFunc2");
  return new Promise(resolve => {
    setTimeout(function setTimeoutCallbackFunc3() {
      console.log("asyncFunc2 promise");
      resolve();
    }, 0);
  })
}
asyncFunc1();
console.log("end");
//這又輸出什麼呢?這個可以說一哈,至於輸出啥子,稍等哈,我複製到瀏覽器執行哈...
// 執行完了,輸出
// start
// new Promise
// asyncFunc1 start
// asyncFunc2
// end
// promise then
// setTimeout
// new Promise setTimeout
// asyncFunc2 promise
// asyncFunc1 end
/* 終於打完了 */ /* 雖然我在瀏覽器中執行後照到打的,但是我能解釋清楚 */ /* 開始裝... */

爲了形象點,畫圖又不會,咋個搞呢?搞個都看得懂的

  • macList = [] //宏任務隊列
  • micList = [] //微任務隊列
  • 比如:macList = [task1, task2, task3, task4, task5, ...]

好了,開始裝了...

  1. 首先,執行棧還是會先執行宏任務,那就去宏任務列表中取,此時的macList = [script],所以取出script執行,macList = []。
  2. 輸出 start。
  3. 遇到setTimout,將回掉加入到宏任務列表中,macList = [setTimeoutCallbackFunc1]。
  4. 執行new Promise代碼,輸出 new Promise,然後遇到setTimeout,加入到紅任務列表中,macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2],然後又遇到resolve,將其回掉加入到微任務列表,micList = [promiseThenCallbackFunc1]。
  5. (請先預備async/await知識)執行asyncFunc1函數,則輸出 asyncFunc1 start,遇到 await asyncFunc2(),則先執行函數,輸出asyncFunc2,然後返回了一個new Promise,new Promise中的代碼回立馬執行,遇到了setTimeout,加入到宏任務隊列,macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2, setTimeoutCallbackFunc3],而後返回到asyncFunc1中,後邊的代碼會全部被封裝到then中,直到asyncFunc2中resolve纔會被執行。
  6. 第5點結束,asyncFunc1執行也就結束,然後輸出 end。
  7. 至此,本輪宏任務結束,輸出了 start, new Promise, asyncFunc1 start, asyncFunc2, end。開始執行微任務。
  8. 然後開始微任務列表挨個執行。此時micList = [promiseThenCallbackFunc1],取出promiseThenCallbackFunc1執行,輸出 promise then。微任務隊列執行完畢,再次執行宏任務。
  9. 此時宏任務列表macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2, setTimeoutCallbackFunc3]。挨個取出執行。
  10. 執行setTimeoutCallbackFunc1,輸出 setTimout
  11. 執行setTimeoutCallbackFunc2,輸出 new Promise setTimout
  12. 執行setTimeoutCallbackFunc3,輸出 asyncFunc2 promise,但此時又遇到resolve,此時會將await asyncFunc2()後的代碼當作回掉,加入到微任務列表中micList = [console.log("asyncFunc1 end")]。宏任務隊列又執行完畢,又開始執行微任務。
  13. 此時微任務micList = [console.log("asyncFunc1 end")],取出執行,輸出 asyncFunc1 end。此時全部執行完畢。

done!!!!
理解得不深,如有錯誤,趕緊指正,非常感謝!!!

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