前言
当我们在面试时,面试官问我们输入url到页面渲染时发生了一些什么过程,许多小伙伴们可能就觉得这不就是读取html,css,js吗,但其实,这其中发生许多事,也有很多考点。这个问题在我们面试过程中十分容易被问到,小伙伴们跟着我这篇文章一起来看看吧。
当我们在浏览器中输入一串url,按下回车之后,最终一套完整的页面就呈现在我们的眼前,包括 DNS 解析、建立 TCP 连接、发送 HTTP 请求、接收响应、解析 HTML、构建 DOM 树、执行 JavaScript、渲染页面等。在这篇文章中我们就来说说浏览器加载到了资源后干的事。
浏览器加载到了资源
- 解析 HTML,生成 DOM 树: 浏览器首先会解析 HTML 代码,将其转换为 DOM(文档对象模型)树。DOM 树是由 HTML 元素节点、文本节点和属性节点等组成的树状结构,表示了 HTML 文档的层次结构和元素之间的关系。
- 解析 CSS,生成 CSSOM 树: 浏览器接着会解析 CSS 代码,将其转换为 CSSOM(CSS 对象模型)树。CSSOM 树是由 CSS 规则、选择器和属性等组成的树状结构,表示了 CSS 样式表的层次结构和样式规则的应用关系。
- 结合 DOM 树和 CSSOM 树,生成 Render Tree: 浏览器会将 DOM 树和 CSSOM 树结合起来,生成渲染树(Render Tree)。渲染树只包含需要显示的可见元素,不包含隐藏的或不可见的元素。渲染树中的每个节点称为渲染对象,它包含了元素的样式和布局信息。
- 计算布局,得到每个结点的几何信息: 浏览器根据渲染树中每个渲染对象的样式信息和布局规则,计算出每个节点的几何信息,包括位置、尺寸、边距等。这个过程称为布局或回流。
- 绘制页面,GPU 绘制: 最后,浏览器使用计算出的几何信息,将渲染树中的每个节点绘制到屏幕上。浏览器通过 GPU(图形处理单元)来加速���制过程,将渲染对象转换为图形和像素,最终呈现为可视化的页面。
在这个过程中,会发生回流重绘,什么是回流和重绘呢?
什么是回流
- 浏览器计算页面布局的过程叫做回流
- 当一个容器的几何属性发生变更时, 页面会发生回流
- 改变窗口的尺寸
- 改变元素的尺寸
- 增加或删除可见的元素
- 页面初次渲染
什么是重绘?
- 将已经计算好布局的容器在屏幕上展现出来
- 元素的非几何属性变化时, 会发生重绘
- 修改背景颜色
- 修改背景图片
- 边框颜色
- 字体颜色
- 回流一定重绘, 重绘不一定回流
我们了解了回流和重绘的机制,我们下面来看一段代码,看看发生了多少次回流:
<div id="app">hello</div> <script> let app = document.getElementById('app') app.style.position = 'relative'; app.style.width = '100px' app.style.height = '200px' app.style.left= '20px' app.style.right = '20px' </script>
小伙伴们是不是跟我当时学一样,脱口而出发生了四次回流,但答案显然是不是的。如果是在老版本的浏览器中,那确实是发生了四次回流,而现如今我们常用的浏览器,都是有一套自己的优化策略的,因为回流是很造成资源消耗的,比如上述代码,这里只发生了一次回流。我们上面的四次操作都修改了容器的几何属性,影响到了元素的布局,浏览器在计算新的布局时会将他们合并在一起,一次性考虑这些属性的变化,所以这里这发生了一次回流
。
app.style.width = '100px' console.log(app.style.width); app.style.height = '200px' console.log(app.style.height); app.style.left= '10px' console.log(app.style.left); app.style.right = '10px' console.log(app.style.right);
看看这段代码,小伙伴们是不是就会说也只发生了一次回流,跟我一开始接触时一模一样,但是这里发生了四次回流
,这就跟我们刚刚所说的浏览器的优化策略有关了。优化策略的底层原理其实是浏览器维护了一个渲染队列,当我们用代码变更元素样式可能导致回流时,渲染队列会先保留这个操作,浏览器会继续执行下面的代码,如果还有相同的行为,会继续进入渲染队列,直到没有元素样式被修改,渲染队列会批量的执行这些操作,所以只发生一次回流。
但有一些js的代码被浏览器碰到了会强制执行渲染队列中的内容,就比如上述代码console.log()
括号里面的代码,他们会强制执行渲染队列,所以这里就回流了四次。那么有哪些代码会强制执行渲染队列呢:
- 盒模型属性(Box Model Properties): 包括
offsetWidth
、offsetHeight
、clientWidth
、clientHeight
,它们提供了有关元素盒模型的信息,即元素在页面中所占据的空间大小、可见内容的大小等。 - 位置属性(Position Properties): 包括
offsetTop
、offsetLeft
、clientTop
、clientLeft
,它们提供了有关元素位置的信息,即元素相对于其父元素或视口的偏移量、边框的大小等。 - 滚动属性(Scroll Properties): 包括
scrollHeight
、scrollWidth
、scrollTop
、scrollLeft
,它们提供了有关元素滚动状态的信息,即元素内容的总大小和当前滚动位置