js 事件循环机制和执行顺序优先级

237 阅读2分钟

个人理解总结

调用栈(同步代码)微任务队列宏任务队列

1. 事件循环的执行顺序示例

假设有以下代码:


console.log("Start");

setTimeout(() => {
    console.log("Timeout callback");
}, 0);

Promise.resolve().then(() => {
    console.log("Promise callback");
});

console.log("End");

执行顺序:

  1. 同步代码 console.log("Start")console.log("End") 优先执行。
  2. setTimeout 的回调被推入 宏任务队列
  3. Promise.then 的回调被推入 微任务队列
  4. 当同步代码完成后,事件循环先执行微任务队列中的 Promise.then,输出 "Promise callback"
  5. 微任务队列清空后,事件循环执行宏任务队列中的 setTimeout,输出 "Timeout callback"

输出顺序为:

Start
End
Promise callback
Timeout callback

2. 事件循环机制

JavaScript是单线程,就是每次只能执行一个任务。为了实现异步任务执行就创造了 事件循环和任务队列。事件循环的工作方式如下 1.js引擎会优先执行同步代码 2.遇到 setTimeout Promise async await后 js引擎会把它们交给浏览器或者nodejs 继续执行同步代码 3.一旦异步任务完成 会将它们回调任务 加入队列 4.同步代码执行完毕后会从 微任务队列和宏任务队列取出任务按照优先级进行执行

3. 执行优先级:微任务 vs 宏任务

JavaScript 中的任务分为 微任务(Microtask)宏任务(Macrotask) 。微任务的优先级高于宏任务,意味着每次事件循环时,微任务队列中的任务会优先被执行。

微任务(Microtask)

  • 常见的微任务Promise.thenasync/awaitqueueMicrotaskMutationObserver
  • 执行时机:当前同步代码和调用栈中的任务完成后立即执行,但在下一个宏任务之前。
  • 特点:事件循环每次检查任务队列时会先清空微任务队列,再执行宏任务队列中的下一个任务。

宏任务(Macrotask)

  • 常见的宏任务setTimeoutsetIntervalsetImmediate(Node.js)、I/O 操作、UI rendering
  • 执行时机:微任务队列中的所有任务清空后,才会执行宏任务队列中的第一个任务。
  • 特点:宏任务队列中的任务按顺序执行,每执行一个宏任务,事件循环会再次检查微任务队列并优先清空微任务。

4. 微任务和宏任务嵌套 你中有我 我中有你 执行顺序如何呢?

案例1

console.log("Start");

setTimeout(() => {
    console.log("Timeout callback");

    Promise.resolve().then(() => {
        console.log("Promise2 callback");
    });
}, 0);

Promise.resolve().then(() => {
    console.log("Promise callback");

    setTimeout(() => {
        console.log("Timeout2 callback");
    
    }, 0);
});

console.log("End");

执行结果是

Start
End
Promise callback
Timeout callback
Promise2 callback
Timeout2 callback

案例2 如果微任务的延迟时间改长结果呢

console.log("Start");

setTimeout(() => {
    console.log("Timeout callback");

    Promise.resolve().then(() => {
        console.log("Promise2 callback");
    });
}, 0);

Promise.resolve().then(() => {
    console.log("Promise callback");

    setTimeout(() => {
        console.log("Timeout2 callback");
    
    }, 2000);
});

console.log("End");

结果 Timeout2 callback延迟了2s打印

Start
End
Promise callback
Timeout callback
Promise2 callback
Timeout2 callback