【javaScript】事件循环机制
事件循环机制
相关文章
事件循环机制
一、JavaScript 的事件循环是什么
JavaScript 的事件循环(Event Loop)机制是一种用于管理异步任务执行顺序的机制。它保证了 JavaScript 单线程环境下的代码执行顺序,并且能够处理异步任务的执行。
事件循环机制由以下几个重要的组成部分构成:
调用栈(Call Stack):
- JavaScript 引擎使用调用栈来追踪代码的执行过程。每当调用一个函数时,该函数会被压入调用栈中,当函数执行完成后,会从调用栈中弹出。这种先进后出(LIFO)的方式确保了代码的顺序执行。
任务队列(Task Queue):
- 任务队列用于存放异步任务的回调函数。包括宏任务队列(macrotask queue)和微任务队列(microtask queue)两种。异步任务的回调函数被添加到任务队列中,等待事件循环将它们取出并执行。
事件循环(Event Loop):
- 事件循环负责从任务队列中取出任务,并将其放入调用栈中执行。事件循环的工作原理是不断地从任务队列中取出任务,如果调用栈为空,则将任务放入调用栈中执行。循环过程会不断重复,直到所有任务都被执行完毕。
二、事件循环的执行过程:
执行同步代码:
- 首先,JavaScript 引擎会执行主线程中的同步代码,将函数调用和执行过程压入调用栈中。
处理微任务:
- 当主线程中的同步代码执行完成后,JavaScript 引擎会检查微任务队列(Microtask Queue)。如果微任务队列不为空,会依次取出微任务并将其放入调用栈中执行,直到微任务队列为空为止。
处理宏任务:
- 接着,JavaScript 引擎会检查宏任务队列(Macrotask Queue)。如果宏任务队列中有任务,则取出一个任务并将其放入调用栈中执行。执行完一个宏任务后,回到第二步继续处理微任务。
重复执行:
- 微任务执行完毕后,JavaScript 引擎会再次检查微任务队列,如果有新的微任务,则继续执行微任务。随后继续检查宏任务队列,执行宏任务。这个过程会持续循环执行,直到任务队列中没有任务为止,事件循环结束。
三、宏任务有哪些
setTimeout 和 setInterval:
- 使用 setTimeout 和 setInterval 函数可以创建宏任务,它们可以在指定的时间间隔后执行回调函数。
DOM 事件:
- 用户交互事件(如点击、鼠标移动、键盘输入等)和其他 DOM 事件(如加载、改变大小、滚动等)都会触发宏任务。
Ajax 请求:
- 发送 Ajax 请求时,回调函数会在请求完成后被添加到宏任务队列中,等待执行。
页面加载:
- 页面加载、资源加载(如图片、样式表、脚本等)也会触发宏任务。
I/O 操作:
- 读写文件、网络请求等 I/O 操作都是宏任务,它们会在操作完成后将回调函数添加到宏任务队列中。
requestAnimationFrame:
- 使用 requestAnimationFrame 可以创建一个在下次浏览器重绘之前执行的宏任务,通常用于实现动画效果。
四、微任务有哪些
Promise 的回调函数:
- 当 Promise 对象状态变为 resolved 或 rejected 时,会执行与之关联的回调函数,这些回调函数会作为微任务被添加到微任务队列中。
MutationObserver:
- 使用 MutationObserver 监听 DOM 的变化,当被监视的 DOM 被修改时,会触发回调函数,该回调函数会作为微任务被添加到微任务队列中。
process.nextTick(仅在 Node.js 中):
- 在 Node.js 环境中,使用 process.nextTick 可以创建一个在当前操作结束后立即执行的微任务。
queueMicrotask API:
- 在浏览器中,可以使用 queueMicrotask API 来添加一个微任务到微任务队列中,以在下一个事件循环迭代时执行。
五、示例
1 |
|
第一轮事件循环
- 执行同步任务
1
console.log(1);
- 注册宏任务
1
2
3
4
5
6
7
8
9setTimeout(function() {
console.log(2);
Promise.resolve().then(function() {
console.log(3);
});
console.log(4);
}, 0);- 注册微任务
1
2
3
4
5
6
7
8
9
10
11
12
13Promise.resolve().then(function() {
console.log(5);
setTimeout(function() {
console.log(6);
}, 0);
Promise.resolve().then(function() {
console.log(7);
});
console.log(8);
});- 执行同步任务
1
console.log(9);
第一轮事件循环结束,输出:1、9。
第一轮事件循环执行很清晰,主要是执行所有同步任务,注册微任务。
第二轮事件循环
- 执行新产生的所有微任务
1
2
3
4
5
6
7Promise.resolve().then(function() {
console.log(5);
console.log(8);
});- 注册宏任务
1
2
3setTimeout(function() {
console.log(6);
}, 0);- 注册微任务
1
2
3Promise.resolve().then(function() {
console.log(7);
});第二轮事件循环结束,输出:5、8
第三轮事件循环
- 执行新产生的所有微任务
1
2
3Promise.resolve().then(function() {
console.log(7);
});- 执行队列中的第一个宏任务
1
2
3
4
5setTimeout(function() {
console.log(2);
console.log(4);
}, 0);第三轮事件循环结束,输出:7、2、4
第四轮事件循环
- 执行新产生的所有微任务
1
2
3
4Promise.resolve().then(function() {
console.log(3);
});- 执行队列中的第一个宏任务
1
2
3setTimeout(function() {
console.log(6);
}, 0);第三轮事件循环结束,输出:3、6
事件循环结束:完整输出:1、9、5、8、7、2、4、3、6
喜欢这篇文章?打赏一下支持一下作者吧!
【javaScript】事件循环机制
https://www.cccccl.com/20210502/javascript/事件循环机制/