浏览器渲染原理以及海量数据渲染的方法
2025年6月22日
8分钟阅读
2 次浏览
0 条评论
浏览器的渲染原理 浏览器工作流程:构建 DOM -> 构建 CSSOM -> 构建渲染树 -> 布局 -> 绘制。 1. 首先解析接收到的文档,根据文档定义构建一棵 DOM 树,DOM 树是 DOM 元素及属性节点组成的 2. 然后对 CSS 进行解析,生成 CSSOM 规则树 3. 根据 DOM 树和 CSSOM 规则树构建渲染树,渲染树的节点被称为渲染对象,渲染对象是一个包含有颜色和大小等...
浏览器的渲染原理
浏览器工作流程:构建 DOM -> 构建 CSSOM -> 构建渲染树 -> 布局 -> 绘制。
- 首先解析接收到的文档,根据文档定义构建一棵 DOM 树,DOM 树是 DOM 元素及属性节点组成的
- 然后对 CSS 进行解析,生成 CSSOM 规则树
- 根据 DOM 树和 CSSOM 规则树构建渲染树,渲染树的节点被称为渲染对象,渲染对象是一个包含有颜色和大小等属性的矩形,渲染对象和 DOM 元素先对应,但这种对应关系不是一一对应的,不可见的 DOM 元素不会被插入渲染树,还有一些 DOM 元素对应着几个可见的对象,它们一般是一些具有复杂结构的元素,无法用一个矩形来描述
- 当渲染对象被创建并添加到树种,它们并没有位置和大小,所以当浏览器生成渲染树以后,就会根据渲染树来进行布局(也可以叫做回流)。这一阶段浏览器要做的事情就是弄清楚各个节点在页面中的确切位置和大小,通常这一行为也被陈伟“自动重排”
- 布局阶段结束后是绘制阶段,遍历渲染树并调用渲染对象的 paint 方法将它们的内容显示到屏幕上,绘制使用 UI 基础组件
值得注意的是,这个过程是完成的,为了更好的用户体验,渲染引擎将会尽可能早地将内容呈现到屏幕上,并不会等所有的 html 都解析完之后再去构建和布局 render 树,它是解析完一部分就显示一部分内容,同时还可能通过网络下载其他内容
详细资料可以参考: 《浏览器渲染原理》 《浏览器的渲染原理简介》 《前端必读:浏览器内部工作原理》 《深入浅出浏览器渲染原理》
为什么操作 DOM 会慢
因为 DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎的东西,当我们通过 JS 去操作 DOM 的时候,其实这个操作就涉及了两个线程之间的通信,那么势必会带来一些性能上的损耗。操作 DOM 次数一多,也就等于一直在进行线程之间的通信,并且操作 DOM 可能还会带来重绘回流的情况,所以也就导致了性能上的问题。
插入几万个 DOM,如何实现页面不卡顿?
首先我们可能不能一次性将几万个 DOM 全部插入,这样肯定会造成卡顿,所以解决问题的重点是应该如何分批次部分渲染 DOM。
-
很多人都会想到的方式是通过
requestAnimationFrame
循环插入原理:渲染大数据时,合理使用 createDocumentFragment 和 requestAnimationFrame,将操作切分为一小段一小段执行。
documentFragment:是一个虚拟的 Dom 列表,可以储存待处理的 xml 片段(el 元素),因为他不在真实的 Dom 结构中,所以对它所做的操作不会触发浏览器的回流,只会在他插入 dom 的时候触发一次而已。
上面把多个动态生成的 div 插入到了虚拟节点里,在最后完成之后只做了一次插入,这样就只会触发一次回流。
但是在数量太多的时候,哪怕是一次插入,也会因为浏览器渲染不过来导致失去响应,这时候就需要增加一定的时间间隔,可以使用 setTimeout,也可以使用一个 api------requestAnimationFrame
requestAnimationFrame:
特点:
- requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
- 在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的 CPU、GPU 和内存使用量
- requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了 CPU 开销
使用:
requestAnimationFrame 的用法与 settimeout 很相似,只是不需要设置时间间隔而已。requestAnimationFrame 使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给 cancelAnimationFrame 用于取消这个函数的执行
html1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7 <title>Document</title>
8 </head>
9 <body>
10 <ul>
11 渲染数据
12 </ul>
13 </body>
14 <script>
15 setTimeout(() => {
16 //插入十万条数据
17 const total = 100000
18 //一次插入20条,如果觉得性能不好就减少
19 const once = 20
20 //计算渲染数据的次数
21 const loopCount = total / once
22 let countOfRender = 0
23 let ul = document.querySelector('ul')
24 function add() {
25 //使用createDocumentFragment来优化新能,插入不会造成回流
26 const fragment = document.createDocumentFragment()
27 for (let i = 0; i < once; i++) {
28 const li = document.createElement('li')
29 li.innerText = Math.floor(Math.random() * total)
30 fragment.appendChild(li)
31 }
32 ul.appendChild(fragment)
33 countOfRender += 1
34 loop()
35 }
36 function loop() {
37 if (countOfRender < loopCount) {
38 window.requestAnimationFrame(add)
39 }
40 }
41 loop()
42 }, 0)
43 </script>
44</html>
-
虚拟滚动:virtualized scroller
这种技术的原理就是渲染可视区域内的内容,非可见区域的就完全不渲染,当用户当用户在滚动的时候就实时去替换渲染的内容。
从上图中我们可以发现,即使列表很长,但是渲染的 DOM 元素永远只有那么几个,当我们滚动页面的时候就会实时去更新 DOM
react-virtualized就是专门解决这个的库
使用 content-visibility
喜欢这篇文章吗?
加载中...
评论
0 条登录后即可参与评论讨论
加载评论中...
相关文章
目录