Skip to content

js 事件循环(event loop)

JavaScript是单线程语言, 事件循环(eventLoop)是单线程在处理异步事件时进行的一种循环过程。

1. 主线程 > 任务队列

事件循环(Event Loop),它由主线程任务队列两部分组成。主线程负责执行同步任务,而异步任务则通过任务队列进行处理。

在事件循环中,当主线程执行完当前的同步任务后,会检查事件队列中是否有待处理的事件。如果有,主线程会取出事件并执行对应的回调函数。

2. 微任务 > 宏任务

在 JavaScript 中,异步任务可以分为两大类:宏任务(macrotasks)微任务(microtasks)。这两类任务在执行时机和优先级上有所不同。

2.1. 宏任务

宏任务是由宿主环境(如浏览器、Node.js)提供的,常见的宏任务包括:

  • setTimeout()
  • setInterval()
  • setImmediate()(Node.js 特有)
  • I/O 操作(如文件读取、网络请求,但这些通常不会直接体现在 JavaScript 代码中,而是由宿主环境处理)

宏任务的特点是:

  • 它们会在当前执行栈清空后,按照顺序依次执行。
  • 每个宏任务执行完之后,都会检查微任务队列,并执行所有微任务。
  • 浏览器渲染通常发生在宏任务之间。
2.2. 微任务

微任务是由 JavaScript 引擎提供的,常见的微任务包括:

  • async.await
  • Promise.then()、Promise.catch()、Promise.finally()
  • MutationObserver 的回调
  • queueMicrotask() 将一个回调函数添加到微任务队列中。这个回调函数会在当前执行栈清空后、浏览器渲染前被执行,且它的优先级高于宏任务。

微任务的特点是:

  • 它们会在当前执行栈清空后、浏览器渲染前执行。
  • 微任务的优先级高于宏任务,每个宏任务执行完之后,都会先执行所有微任务,然后再进行下一个宏任务的执行。
  • 微任务队列是在每个宏任务执行完之后都会检查的,所以微任务会“插队”到宏任务之间执行。
2.3. 执行顺序
  • 1.执行同步任务(即当前执行栈中的任务)。
  • 2.清空微任务队列,执行所有微任务。
  • 3.执行下一个宏任务。
  • 4.重复步骤 2 和 3,直到所有任务都执行完毕。

3. 示例

3.1. 示例
JavaScript
console.log('script start');

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

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');

// 输出顺序:
// script start [同步任务]
// script end [同步任务]
// promise1 [微任务]
// promise2 [微任务]
// setTimeout [宏任务]
3.2. 示例
JavaScript
console.log(1);

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

console.log(3);

new Promise((resolve) => {
    console.log(4);
    resolve();
    console.log(5);
}).then(() => {
    console.log(6);
});

console.log(7);


// 输出顺序:
// 1 [同步任务]
// 3 [同步任务]
// 4 [同步任务]
// 5 [同步任务]
// 7 [同步任务]
// 6 [微任务]
// 2 [宏任务]

京ICP备2024093538号-1