Appearance
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 [宏任务]