【前端】探索JavaScript事件循环机制 [ 前端 ]
晚安月亮 文章 正文

椰奶冻
{{nature("2024-09-27 15:03:22")}}更新1. 什么是事件循环机制?
JS 中的事件循环(Event Loop)是一种用于管理和调度异步任务执行的机制。它使得 JS 可以处理异步操作,如定时器、事件处理、网络请求等,而不会阻塞主线程的执行。
2. 说一下什么是宏任务微任务,为什么要定义这两种任务类型?
宏任务(macro tasks)和微任务(micro tasks)是 JavaScript 引擎中用于管理异步任务执行顺序的两种任务类型。
宏任务(Macro tasks): 是指那些需要在主线程中执行的任务,它们包括但不限于:
- 定时器任务(Timers):通过 setTimeout、setInterval 创建的任务。
- I/O 操作任务(I/O operations):例如文件读写、网络请求等异步操作。
- 渲染事件(UI Rendering):处理用户交互事件(例如鼠标点击、键盘事件等)的任务。
- 事件处理器任务(Event handlers):事件监听器、事件回调等。
微任务(Micro tasks): 是指在当前任务执行完成后立即执行的任务,它们通常包括:
- Promise 回调(Promise callbacks):使用 Promise 对象的 then 方法添加的回调函数。
- MutationObserver 回调:通过 MutationObserver 观察 DOM 变化并触发的任务。
- process.nextTick(在 Node.js 环境中):在事件循环的当前回合结束时执行的任务。
宏任务和微任务的引入使得 JavaScript 引擎能够更好地处理异步任务。
宏任务用于表示一组相对较大的任务单元,而微任务用于表示一组相对较小、优先级较高的任务单元。
通过微任务,我们可以在宏任务执行完成后立即执行一些重要的任务,如更新 UI、处理 Promise 的回调等,以提高应用的响应速度和用户体验。
3. 例题:
1.
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0);
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
console.log('script end');
答案:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
过程:
1. 同步任务(同步代码执行)
首先,所有同步任务按顺序执行。
- 第 1 步:
console.log('script start');
- 输出:
script start
- 输出:
- 第 2 步:调用
async1
函数。- 进入
async1
函数,console.log('async1 start');
- 输出:
async1 start
- 遇到
await async2()
,async2
被调用。
- 进入
- 第 3 步:进入
async2
函数,console.log('async2');
- 输出:
async2
async2
函数执行结束,回到async1
。
- 输出:
- 第 4 步:
await
表达式遇到一个Promise
,async1
函数暂停并将控制权交回主线程,继续执行后面的同步代码。 - 第 5 步:创建一个
Promise
,立即执行其回调函数,console.log('promise1');
- 输出:
promise1
- 输出:
- 第 6 步:
Promise
的回调函数执行完毕,注册了一个.then
回调到微任务队列。 - 第 7 步:
console.log('script end');
- 输出:
script end
- 输出:
2. 微任务(Microtasks)队列处理
主线程上的同步任务执行完毕,开始处理微任务队列。
- 第 8 步:
async1
的await
表达式完成(此时它已经变成一个Promise
),恢复执行async1
函数的后续代码。- 执行
console.log('async1 end');
- 输出:
async1 end
- 执行
- 第 9 步:
Promise.then
回调执行。- 执行
console.log('promise2');
- 输出:
promise2
- 执行
3. 宏任务(Macrotasks)队列处理
微任务队列清空后,开始处理宏任务队列中的任务。
-
第 10 步 :处理
setTimeout
的回调函数。
- 执行
console.log('setTimeout');
- 输出:
setTimeout
- 执行
2.
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("6");
setTimeout(()=>{console.log(8);},0)
resolve('success')
console.log(7);
}, 0);
console.log(2);
});
setTimeout(()=>{
console.log(5);
},0)
promise.then((res)=>{
console.log(res);
})
console.log(4);
答案:
1
2
4
5
6
7
success
8
1. 执行宏任务(Macrotask
)
- 遇到第一个宏任务(
setTimeout
回调),执行回调函数:- 输出:
5
- 输出:
- 执行下一个宏任务(
Promise
内的setTimeout
回调),执行回调函数:- 输出:
6
- 注册一个新的
setTimeout
,将其加入到宏任务队列中。 - 调用
resolve('success')
,将then
回调加入到微任务队列中。 - 输出:
7
- 输出:
2. 执行微任务(Microtask
)
-
执行微任务队列中的回调函数:
- 执行
promise.then
的回调,输出
res
的值:
success
- 输出:
success
3. 执行下一个宏任务(Macrotask
)
-
执行最后一个
setTimeout
回调:
- 输出:
8
- 输出:
{{nature('2022-06-23 23:10:58')}} {{format('1477')}}人已阅读
{{nature('2023-02-03 16:12:08')}} {{format('1397')}}人已阅读
{{nature('2024-05-29 15:14:38')}} {{format('1025')}}人已阅读
{{nature('2024-05-24 15:20:21')}} {{format('905')}}人已阅读
目录
标签云
一言
评论 0
{{userInfo.data?.nickname}}
{{userInfo.data?.email}}