事件循環(huán)(Event Loop)練習(xí)題

事件循環(huán)(Event Loop)練習(xí)題,幫助你鞏固對(duì)宏任務(wù)、微任務(wù)和異步執(zhí)行順序的理解。每個(gè)題目都附有詳細(xì)解析:

題目1:混合 Promise 和 setTimeout

console.log('Start');

setTimeout(() => console.log('Timeout 1'), 0);

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

Promise.resolve().then(() => console.log('Promise 2'));

console.log('End');

<details>
<summary>查看答案與解析</summary>

輸出順序:

Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2

解析:

  1. 同步代碼:StartEnd
  2. 微任務(wù)隊(duì)列:
    • 第一個(gè) Promise:輸出 Promise 1,添加新的宏任務(wù)(Timeout 2)
    • 第二個(gè) Promise:輸出 Promise 2
  3. 宏任務(wù)隊(duì)列:
    • 執(zhí)行第一個(gè) setTimeout:輸出 Timeout 1
    • 執(zhí)行第二個(gè) setTimeout:輸出 Timeout 2
      </details>

題目2:多層異步嵌套

console.log('Script start');

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

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
  setTimeout(() => console.log('inner setTimeout'), 0);
});

console.log('Script end');

<details>
<summary>查看答案與解析</summary>

輸出順序:

Script start
Script end
promise1
promise2
setTimeout
inner setTimeout

解析:

  1. 同步代碼:Script startScript end
  2. 微任務(wù)隊(duì)列:
    • 第一個(gè) then:輸出 promise1,返回新 Promise
    • 第二個(gè) then:輸出 promise2,添加新宏任務(wù)
  3. 宏任務(wù)隊(duì)列:
    • 第一個(gè) setTimeout:輸出 setTimeout
    • 第二個(gè) setTimeout:輸出 inner setTimeout
      </details>

題目3:async/await 與 Promise 混合

async function async1() {
  console.log('A');
  await async2();
  console.log('B');
}

async function async2() {
  console.log('C');
  await new Promise(resolve => {
    console.log('D');
    resolve();
  });
  console.log('E');
}

console.log('F');

setTimeout(() => console.log('G'), 0);

async1();

new Promise(resolve => {
  console.log('H');
  resolve();
}).then(() => console.log('I'));

console.log('J');

<details>
<summary>查看答案與解析</summary>

輸出順序:

F
A
C
D
H
J
E
B
I
G

解析:

  1. 同步代碼:FACDHJ
  2. 微任務(wù)隊(duì)列:
    • async2 的 await:輸出 E
    • async1 的 await:輸出 B
    • Promise 的 then:輸出 I
  3. 宏任務(wù):G
    </details>

題目4:復(fù)雜微任務(wù)鏈

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve()
  .then(() => {
    console.log('3');
    return Promise.resolve('4').then(data => {
      console.log(data);
      return '5';
    });
  })
  .then(data => console.log(data));

Promise.resolve()
  .then(() => console.log('6'))
  .then(() => console.log('7'));

console.log('8');

<details>
<summary>查看答案與解析</summary>

輸出順序:

1
8
3
6
4
7
5
2

解析:

  1. 同步代碼:18
  2. 微任務(wù)隊(duì)列:
    • 第一個(gè) Promise 鏈:345
    • 第二個(gè) Promise 鏈:67
    • 注意:return Promise.resolve 會(huì)創(chuàng)建額外的微任務(wù)
  3. 宏任務(wù):2
    </details>

題目5:事件循環(huán)綜合題

console.log('Start');

document.addEventListener('click', () => {
  console.log('Click');
  Promise.resolve().then(() => console.log('Microtask in Click'));
});

setTimeout(() => {
  console.log('Timeout');
  Promise.resolve().then(() => console.log('Microtask in Timeout'));
}, 0);

Promise.resolve().then(() => console.log('Promise 1'));

console.log('End');

<details>
<summary>查看答案與解析</summary>

初始輸出順序(不觸發(fā)點(diǎn)擊):

Start
End
Promise 1
Timeout
Microtask in Timeout

如果觸發(fā)點(diǎn)擊事件:

Start
End
Promise 1
Timeout
Microtask in Timeout
Click
Microtask in Click

解析:

  1. 同步代碼:StartEnd
  2. 微任務(wù):Promise 1
  3. 宏任務(wù):Timeout 及其微任務(wù) Microtask in Timeout
  4. UI事件(點(diǎn)擊)作為宏任務(wù)處理
  5. 每個(gè)宏任務(wù)后都會(huì)清空微任務(wù)隊(duì)列
    </details>

解題技巧總結(jié):

  1. 同步代碼總是最先執(zhí)行
  2. 微任務(wù)(Microtask)執(zhí)行時(shí)機(jī)
    • 在每個(gè)宏任務(wù)之后
    • 在DOM渲染之前
    • 清空整個(gè)微任務(wù)隊(duì)列(包括嵌套產(chǎn)生的)
  3. 宏任務(wù)(Macrotask)執(zhí)行時(shí)機(jī)
    • 一次事件循環(huán)只執(zhí)行一個(gè)宏任務(wù)
    • 包括:setTimeout、setInterval、I/O、UI渲染、事件回調(diào)
  4. async/await 本質(zhì)
    • await 之前的代碼是同步的
    • await 之后的代碼相當(dāng)于 .then() 回調(diào)
  5. Promise 鏈
    • 每個(gè) .then() 都會(huì)創(chuàng)建新的微任務(wù)
    • return Promise 會(huì)創(chuàng)建額外的微任務(wù)

建議你嘗試自己分析這些題目,畫(huà)出事件循環(huán)的流程圖,然后對(duì)照解析驗(yàn)證理解。掌握這些模式后,你就能準(zhǔn)確預(yù)測(cè)任何JavaScript異步代碼的執(zhí)行順序了!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容