iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0
Modern Web

從技術文章深入學習 JavaScript系列 第 15

Day 15 [EventLoop 02] Eventloop不可怕,可怕的是遇上Promise

  • 分享至 

  • xImage
  •  

文章選自

作者:小美娜娜

連接:https://juejin.im/post/6844903808200343559

來源:掘金

附註

本篇文章有提到node EventLoop,但我僅針對瀏覽器去做分析

版本一:得心應手版

題目

setTimeout(()=>{
   console.log(1) 
},0)
Promise.resolve().then(()=>{
   console.log(2) 
})
console.log(3) 

分析

階段一

1. 遇到setTimeout放入宏任務隊列,碰到Promise then將它放進微任務隊列
2. 打印3
3. 同步執行完畢

https://ithelp.ithome.com.tw/upload/images/20200927/20124350fS5gn0v58P.png

宏任務與微任務隊列:

![https://ithelp.ithome.com.tw/upload/images/20200927/20124350Ys24lUUW2t.png](https://ithelp.ithome.com.tw/upload/images/20200927/20124350Ys24lUUW2t.png)

階段二

1. 觀察微任務隊列,發現有2
2. 打印2
3. 微任務全數完成,執行宏任務打印出1

https://ithelp.ithome.com.tw/upload/images/20200927/20124350BxfqLuHfZb.png

版本二:游刃有餘版

題目

setTimeout(() => {
  console.log(1)
}, 0)
let a = new Promise((resolve) => {
  console.log(2)
  resolve()
}).then(() => {
  console.log('Promise3')
}).then(() => {
  console.log('Promise4')
})
console.log(5) 

分析

階段一

  1. 看到setTimeout將它放進宏任務隊列
  2. new了一個Promise實例,但Promise的executer是同步,因此這裡打印出2,接下來看到Promise3 then 將它放進微任務隊列繼續執行(因為第二個then需等第一個完成,因此會先無視它)
  3. 打印出5

https://ithelp.ithome.com.tw/upload/images/20200927/20124350nZfrXKfrj1.png

宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/20124350srgu8JMYxl.png

階段二

  1. 觀察微任務隊列,有Promise3 then,執行它,打印出Promsie3。
  2. 打印出Promise3之後發現下面還有一個Promise4 then(鍊式調用),將它放進微任務隊列

https://ithelp.ithome.com.tw/upload/images/20200927/20124350rdOMTafCdT.png

目前宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/20124350xJX4AQLkrZ.png

階段三

  1. 檢查微任務隊列是否為空,發現Promise4 then,執行它打印出Promise4
  2. 微任務隊列終於變空的,執行宏任務隊列(注意每執行完一個宏任務就要檢查為任務隊列是否為空)打印出1

https://ithelp.ithome.com.tw/upload/images/20200927/20124350zsFHT6K5G8.png

版本三:爐火純青版

題目

new Promise((resolve, reject) => {
  console.log("promise1")
  resolve()
}).then(() => {
  console.log("then11")
  new Promise((resolve, reject) => {
    console.log("promise2")
    resolve()
  }).then(() => {
    console.log("then21")
  }).then(() => {
    console.log("then23")
  })
}).then(() => {
  console.log("then12")
})

分析

階段一

  1. Promsie executor,所以打印promise1,並將then11放進微任務

https://ithelp.ithome.com.tw/upload/images/20200927/20124350uju2ygzl9I.png

目前宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/20124350WllR7nfzFl.png

階段二

  1. 執行then11區塊,並打印出then11
  2. 又創建了一個Promise實例,因為executor為同步,所以在此打印promise2
  3. 碰到then21,所以將它放進微任務隊列裡,第二個then23因為要等then21區塊執行完先跳過
  4. then11區塊執行完成,因此將Promise then12放進微任務隊列裡面

https://ithelp.ithome.com.tw/upload/images/20200927/20124350B6EszDijb2.png

目前宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/2012435000pCmCn3C3.png

階段三

  1. 照隊列邏輯,先進先出,因此先執行Promise then21區塊,打印出then21,然後出隊列
  2. 因為Promise the21執行完成,因此發現then23 將它放到隊列裡
  3. 順著下來執行Promise then12 區塊,因此又打印出then12

https://ithelp.ithome.com.tw/upload/images/20200927/20124350E7QXC4OPQi.png

目前宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/20124350akZA91kYCL.png

階段四

  1. 觀察微任務隊列,發現Promise then23,執行它並打印出then23
  2. 隊列皆為空,完成

https://ithelp.ithome.com.tw/upload/images/20200927/20124350EX9phXkJ0L.png

版本四:登峰造極版

題目

async function async1() {
    console.log("async1 start");
    await  async2();
    console.log("async1 end");
}

async  function async2() {
    console.log( 'async2');
}

console.log("script start");

setTimeout(function () {
    console.log("settimeout");
},0);

async1();

new Promise(function (resolve) {
    console.log("promise1");
    resolve();
}).then(function () {
    console.log("promise2");
});
console.log('script end'); 

分析

階段一

  1. 聲明了兩個函數,然後打印 script start

  2. 接下來碰到宏任務setTimeout,將它放進宏任務隊列

  3. 執行async1,回去找他聲明時候的樣子,接著打印出async1 start以及async2,並將以下為異步放進為任務隊列裡

async function async1() {
    // 這裡以下為同步函數(包括await後面)
    console.log("async1 start");
    await  async2();
    // 以下為異步
    console.log("async1 end");
}

async  function async2() {
    console.log( 'async2');
}
  1. 打印 promise1,並將promise2 then放入微任務隊列裡

  2. 打印 script end

https://ithelp.ithome.com.tw/upload/images/20200927/20124350r6qy3HCcCL.png

目前宏任務與微任務隊列:

https://ithelp.ithome.com.tw/upload/images/20200927/2012435046EXE3E2p6.png

階段二

  1. 執行async1 end的區塊,並打印出async1 end
  2. 微任務隊列裡還有proimse2 then,執行它
  3. 打印出promise2
  4. 執行宏任務,並打印出settimeout

https://ithelp.ithome.com.tw/upload/images/20200927/20124350yalDcdtHiP.png

版本五:究極變態版

因此題提到node的EventLoop,因此我暫時跳過。有興趣的人可以解看看

代碼

async function async1() {
    console.log("async1 start");
    await  async2();
    console.log("async1 end");
}
async  function async2() {
    console.log( 'async2');
}
console.log("script start");
setTimeout(function () {
    console.log("settimeout");
});
async1()
new Promise(function (resolve) {
    console.log("promise1");
    resolve();
}).then(function () {
    console.log("promise2");
});
setImmediate(()=>{
    console.log("setImmediate")
})
process.nextTick(()=>{
    console.log("process")
})
console.log('script end'); 


上一篇
Day 14 [異步03] 八段代碼徹底掌握Promise
下一篇
Day 16 [淺拷貝] 淺拷貝與深拷貝
系列文
從技術文章深入學習 JavaScript29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言