深度剖析Js中的代碼執(zhí)行順序

在JavaScript中,代碼的執(zhí)行順序涉及事件循環(huán)(Event Loop)、調用棧(Call Stack)、任務隊列(Task Queue)等核心機制。以下是分層次的解析和典型示例:

同步代碼
  ↓
微任務隊列(全部執(zhí)行)
  ↓
渲染(如有需要)
  ↓
宏任務隊列(取一個執(zhí)行)
  ↓
重復循環(huán)

掌握這些規(guī)則后,可通過以下步驟分析任何執(zhí)行順序問題:

標記所有同步代碼

識別微任務(Promise.then, MutationObserver, queueMicrotask)

識別宏任務(setTimeout, setInterval, I/O操作, UI渲染等)

按規(guī)則循環(huán)處理隊列

復雜場景示例

async function async1() {
  console.log('async1 start'); // 同步
  await async2(); // 相當于Promise.resolve(async2()).then(...)
  console.log('async1 end'); // 微任務
}

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

console.log('script start'); // 同步
async1();
new Promise(resolve => {
  console.log('Promise'); // 同步
  resolve();
}).then(() => {
  console.log('Promise then'); // 微任務
});
console.log('script end'); // 同步

/* 輸出:
  script start → async1 start → async2 → Promise → script end →
  async1 end → Promise then
*/

這里核心概念修正:
await 的執(zhí)行分為兩個階段:
1. await async2() 會立即執(zhí)行 async2() 函數(shù)內的同步代碼(即 console.log('async2')),
此時不會產生任何任務隊列操作。
2. 隱式創(chuàng)建 Promise 并暫停 async1
   如果 async2() 返回非 Promise,JS 會用 Promise.resolve() 包裝它
   await 的本質:將 async1 函數(shù)內await 之后的代碼
(即 console.log('async1 end'))包裝成這個 Promise 的 .then() 回調,也就是放入微任務隊列

特殊場景注意

  1. Promise構造函數(shù)是同步的
new Promise(resolve => {
  console.log('Promise executor'); // 同步!
  resolve();
}).then(() => console.log('then')); // 微任務
  1. 任務隊列的優(yōu)先級
    宏任務隊列中:
    交互事件(如click) > 網(wǎng)絡回調 > 定時器
  2. Node.js差異
    Node中的process.nextTick優(yōu)先級高于微任務:
Promise.resolve().then(() => console.log('Promise'));
process.nextTick(() => console.log('nextTick'));
// 輸出:nextTick → Promise

再看一個例子

console.log('1');

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

Promise.resolve().then(() => {
  console.log('4');
  setTimeout(() => console.log('5'), 0);
});

console.log('6');

/* 答案:
  1 → 6 → 4 → 2 → 3 → 5
  執(zhí)行流程:
  1. 同步代碼:1, 6
  2. 微任務隊列:4(執(zhí)行時把5的定時器加入宏任務隊列)
  3. 宏任務隊列:2(執(zhí)行時把3加入微任務隊列)
  4. 微任務隊列:3
  5. 宏任務隊列:5
*/

再看一個例子【混合宏任務與嵌套 Promise】

console.log('Start');

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

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

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

console.log('End');
// Start → End → Promise 2 → Timeout 1 → Promise 1 → Timeout 2 → Timeout 3

關鍵點:

  1. 微任務中注冊的宏任務:在微任務執(zhí)行期間注冊的宏任務(如 Timeout 3),會被添加到當前宏任務隊列的末尾。
    它需要等待當前所有已存在的宏任務(如 Timeout 1 和 Timeout 2)執(zhí)行完畢后才會執(zhí)行。
  2. 執(zhí)行順序的本質:
同步代碼 → 微任務 → 宏任務1 → 宏任務1觸發(fā)的微任務 → 宏任務2 → 宏任務3...
  1. 為什么 Timeout 3 最后執(zhí)行?
    因為它是前一個微任務(Promise 2)執(zhí)行時才注冊的,而 Timeout 1 和 Timeout 2 早已在同步階段就注冊了。

類比助記

把任務隊列想象成一個快遞分揀系統(tǒng):

同步代碼:立即處理的加急快遞。

微任務:分揀員手頭正在打包的包裹(必須全部打完才能處理新快遞)。

宏任務:排隊等待的普通快遞。

在打包時新收到的快遞(如 Timeout 3)會被放到普通隊列的隊尾,按順序處理。

再來一個例子【混合事件循環(huán)優(yōu)先級】

document.addEventListener('click', () => console.log('Click'));

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

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(() => console.log('Fetch'));

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

// 模擬用戶點擊(實際點擊時輸出可能不同)
document.dispatchEvent(new Event('click'));
console.log('Sync end');
// Click → Sync end → Promise → Fetch → Timeout
//手動觸發(fā)的 click 是同步的,真實點擊會優(yōu)先于 Fetch 和 Timeout。
//微任務 Promise 先于宏任務 Fetch 和 Timeout 執(zhí)行。

Promise.all 與微任務

console.log('Start');

Promise.all([
  new Promise(resolve => {
    setTimeout(() => {
      console.log('Timeout 1');
      resolve();
    }, 0);
  }),
  Promise.resolve().then(() => console.log('Promise 1')),
]).then(() => {
  console.log('Promise.all resolved');
});

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

console.log('End');
// Start → End → Promise 1 → Promise 2 → Promise 3 → Timeout 1 → Promise.all resolved
//Promise.all 需等待所有子 Promise 完成,包括宏任務 Timeout 1。
//獨立的微任務鏈(Promise 2 → Promise 3)優(yōu)先執(zhí)行。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容