浏览器的事件循环机制
浏览器的事件循环机制
核心概念
-
事件循环(Event Loop)
- 使得 JavaScript 异步编程成为可能的机制
- 负责监听调用栈和消息队列,当调用栈为空时,将消息队列中的任务推入调用栈执行
-
调用栈(Call Stack)
- 用于追踪函数执行的栈结构
- 当函数执行时,会被添加到栈顶;执行完毕后,会从栈顶移除
-
消息队列(Message Queue)
- 存储待处理消息的队列
- 消息可以是用户产生的事件、定时器到期等
事件循环过程
-
执行全局脚本
- 首先执行全局代码,将全局代码压入调用栈
-
事件循环启动
- 全局代码执行完毕后,调用栈变为空,事件循环开始工作
-
从消息队列中取出任务
- 事件循环从消息队列中取出一个任务
-
执行任务
- 将取出的任务压入调用栈,执行任务
-
任务执行完毕
- 任务执行完毕后,从调用栈中移除
-
重复步骤 3-5
- 持续监听消息队列,重复上述过程
宏任务与微任务
-
宏任务(Macro Task)
- 如:
setTimeout
、setInterval
、I/O、UI 渲染等 - 每次事件循环只从宏任务队列中取出一个任务执行
- 如:
-
微任务(Micro Task)
- 如:
Promise.then
、MutationObserver
、queueMicrotask
等 - 当前宏任务执行完毕后,会执行所有队列中的微任务,再执行下一个宏任务
- 如:
执行顺序
- 执行同步代码,这属于宏任务
- 执行栈为空,查询是否有微任务需要执行
- 执行所有微任务
- 必要的话渲染 UI
- 开始下一轮 Event Loop,执行宏任务中的异步代码,如
setTimeout
中的回调函数
特点
- 非阻塞
- 异步任务不会阻塞代码的执行,提高了代码的执行效率
- 顺序控制
- 通过事件循环机制,JavaScript 能够控制事件处理、定时器执行等的顺序