JavaScript中的事件循环机制是如何影响代码执行顺序的?

同步代码先执行,微任务优先于宏任务。JavaScript 通过事件循环协调任务:同步任务入栈执行;异步任务分微任务(如 Promise.then)和宏任务(如 setTimeout)进入对应队列;同步执行完后,先清空微任务队列,再取宏任务执行。例如 console.log('1')、setTimeout、Promise.then、console.log('4') 的输出顺序为 1 → 4 → 3 → 2,因 '1' 和 '4' 同步执行,Promise 回调为微任务,在本轮末尾执行,setTimeout 为宏任务延至下轮执行。事件循环持续检查调用栈,清空微任务后执行宏任务,如此反复。掌握此机制是理解 JS 异步关键。

JavaScript 是单线程语言,依靠事件循环(Event Loop)机制来协调代码的执行顺序,特别是在处理异步操作时。它决定了同步代码、异步回调、微任务和宏任务的执行优先级。

同步代码优先执行

JavaScript 会按代码书写顺序立即执行所有同步任务。这些任务运行在主线程上,形成调用栈,逐个完成。

例如:

    console.log('A');
console.log('B');

输出顺序一定是 A → B,因为它们是同步代码,直接入栈执行。

异步任务进入任务队列

当遇到异步操作(如 setTimeoutsetIntervalPromise.thenfetch 等),它们不会立即执行,而是被放入不同的任务队列中等待处理。

事件循环持续检查调用栈是否为空。一旦空闲,就开始从队列中取出任务执行。

  • 宏任务(Macrotask):包括 setTimeoutsetInterval、I/O、UI 渲染等。
  • 微任务(Microtask):包括 Promise.then/catch/finallyqueueMicrotaskMutationObserver 等。

微任务优先于宏任务执行

每次同步代码执行完毕后,事件循环会先清空当前所有的微任务队列,再执行下一个宏任务。

看一个典型例子:

    console.log('1');

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

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

console.log('4');

输出结果是:1 → 4 → 3 → 2

说明:

  • '1' 和 '4' 是同步代码,最先输出。
  • Promise 的 then 回调是微任务,在本轮事件循环末尾执行。
  • setTimeout 是宏任务,要等到下一轮事件循环才执行。

事件循环的工作流程总结

整个执行流程可以概括为:

  1. 执行全局同步代码,产生执行栈。
  2. 异步任务被挂起,对应的回调进入相应队列(微任务或宏任务)。
  3. 同步代码执行完,调用栈清空。
  4. 立即执行所有当前可用的微任务。
  5. 取一个宏任务执行(如 setTimeout 回调),然后再次清空微任务队列。
  6. 重复以上过程。

基本上就这些。理解微任务先于宏任务执行,是掌握 JavaScript 异步行为的关键。不复杂但容易忽略。