JavaScript的事件循环-EventLoop

JavaScript的事件循环-EventLoop

JavaScript的事件循环是一道很古老很常见的面试题,也是前端开发必须明白的一个知识点。事件循环的说法很多,很早的一种说法的宏任务微任务去进行轮询处理异步任务。后面开始有线程队列的说法。说是浏览器的渲染主线程去按照一定的优先级去调用执行多个队列内的任务,javascript代码在执行时,有同步代码直接在渲染主线程内执行,异步代码根据相应的优先级放进对应的队列等待渲染主线程的执行。

什么是浏览器的渲染主线程,它都干什么?

浏览器的渲染主线程是浏览器中负责处理页面渲染和交互的核心线程之一。它负责执行各种任务,包括处理 DOM(文档对象模型)操作、CSS 解析、布局计算、绘制页面元素以及处理用户输入等。以下是渲染主线程需要处理的一些主要任务:

  1. HTML 解析: 当浏览器接收到 HTML 文档时,渲染主线程负责解析 HTML,并将其转换成 DOM 树。

  2. CSS 解析: 解析 CSS 样式表,构建 CSSOM 树(CSS Object Model),用于确定每个元素的样式信息。

  3. 渲染树的构建: 结合 DOM 树和 CSSOM 树,生成渲染树(Render Tree),渲染树中包含了需要渲染的 DOM 元素以及其对应的样式信息。

  4. 布局计算: 根据渲染树中每个元素的尺寸、位置和样式等信息,计算出页面中各个元素的布局(也称为重排或回流)。

  5. 绘制: 将页面元素根据其布局信息绘制到屏幕上,生成像素信息。

  6. 交互处理: 监听用户的交互事件,如鼠标点击、滚动、键盘输入等,并相应地触发相应的事件处理函数。

  7. 动画处理: 如果页面中包含 CSS 动画或 JavaScript 实现的动画,渲染主线程需要及时更新页面状态,实现动画效果。

  8. 网络请求和资源加载: 渲染主线程也负责发起网络请求,获取页面所需的外部资源,如图片、脚本、样式表等,并在资源加载完成后将其渲染到页面上。

这些任务在渲染主线程中按照优先级顺序执行,以确保页面能够尽快呈现给用户并保持良好的交互响应性。然而,需要注意的是,如果某个任务耗时过长或阻塞了主线程,可能会导致页面渲染停顿,用户体验下降。因此,开发者需要注意优化页面性能,尽量减少主线程的阻塞和负载。

浏览器渲染主线程事件循环相关主要需要知道哪些队列?以及这些队列的优先级?

在 Chrome 浏览器的事件循环中,存在多个队列,其中至少包括以下三种队列:延时队列交互队列微队列。让我们详细了解它们的优先级以及 JavaScript 中哪些操作对应于这些队列。

  1. 延时队列

    • 用于存放计时器到达后的回调任务。
    • 优先级:
    • 对应的 JavaScript 操作:setTimeoutsetInterval
  2. 交互队列

    • 用于存放用户操作后产生的事件处理任务。
    • 优先级:
    • 对应的 JavaScript 操作:例如点击事件、键盘事件、鼠标事件等。
  3. 微队列

    • 用于存放需要尽快执行的任务。
    • 优先级:最高
    • 对应的 JavaScript 操作:主要是使用 PromiseMutationObserver

现在,让我们来看一下这些队列的处理顺序:

  1. 当 JavaScript 代码执行时,遇到异步任务(例如 setTimeout、用户操作、Promise 等)时,这些任务会被添加到相应的队列中。
  2. 首先,微队列中的任务会被优先执行,确保这些任务在下一次事件循环之前得到处理。
  3. 接下来,交互队列中的任务会被执行,处理用户操作产生的事件。
  4. 最后,延时队列中的任务会被执行,即计时器到达后的回调。

总之,JavaScript 的事件循环机制保证了异步任务的有序执行,避免了阻塞主线程,从而保持了浏览器的流畅运行。

代码示例

理解延时队列、交互队列和微队列的优先级执行顺序是非常重要的,因为它关系到 JavaScript 中异步任务的执行顺序。

javascript 复制代码
console.log('Start');

setTimeout(() => console.log('Timeout 1'), 0);

Promise.resolve().then(() => console.log('Microtask 1'));

document.addEventListener('click', () => console.log('Click event'));

console.log('End');

执行顺序分析:

  1. 同步任务:执行 console.log('Start')console.log('End'),打印 "Start" 和 "End"。
  2. 微任务队列:执行 Promise.resolve().then(() => console.log('Microtask 1')),打印 "Microtask 1"。
  3. 延时队列:执行 setTimeout(() => console.log('Timeout 1'), 0),打印 "Timeout 1"。
  4. 交互队列:等待用户点击,当用户点击时,执行 document.addEventListener('click', () => console.log('Click event')),打印 "Click event"。

执行结果:

相关推荐
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte7 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc