一、简化框架结构
二、进程和线程
1.进程和线程
进程(Process) 是计算机中正在运行的一个程序的实例。每个进程都有自己的地址空间、代码、数据和状态,它们之间是独立的,互相之间不能直接访问。进程是操作系统分配资源的最小单位,它们拥有独立的系统资源,比如内存空间、文件句柄、网络连接等。每个进程都有自己的进程标识符(PID),用于区分不同的进程。
线程(Thread) 是进程中的一个独立执行单元,它是进程中的一个实体,负责执行进程的一部分代码。一个进程可以包含多个线程,它们共享进程的内存空间和系统资源。线程是轻量级的执行单元,创建和销毁的开销较小。线程之间的通信相对于进程之间的通信来说也更加高效和快速。
进程之间是独立的,而线程之间共享进程的资源。由于线程之间共享资源,因此线程之间的同步和互斥问题需要特别注意。同时,线程的并发执行也可能导致一些并发问题,比如死锁和竞态条件等。
2.单进程结构浏览器
1.简化结构
2.缺点
单进程结构浏览器的主要缺点是稳定性和性能方面的问题。
- 稳定性问题: 由于单进程结构的浏览器中所有标签页和扩展程序都在同一个进程中运行,一个标签页或扩展程序崩溃可能会导致整个浏览器崩溃。因此,单进程结构的浏览器的稳定性相对较差,用户可能需要经常重新启动浏览器。
- 性能问题: 由于单进程结构浏览器中所有标签页和扩展程序都共享同一个进程,因此它们之间的资源调度存在竞争。如果其中一个标签页或扩展程序占用了大量的计算资源或内存,会导致整个浏览器变得非常慢甚至崩溃。
另外,单进程结构浏览器还存在安全隐患。由于不同的标签页和扩展程序共享同一个进程,一个恶意的网站或扩展程序可能会窃取其他标签页或扩展程序的数据,或者在浏览器中执行恶意代码。
3.多进程结构浏览器
现代多进程浏览器通常包含以下几个进程:
- 浏览器进程:负责维护浏览器的用户界面、地址栏、书签栏、前进后退按钮等。同时,该进程也负责协调其他进程之间的通信,包括创建和销毁渲染进程、插件进程和扩展程序进程等。浏览器进程还会维护一些浏览器级别的资源,如 cookies 和存储等。
- 渲染进程:负责处理每个标签页中的网页内容。当用户在地址栏输入 URL 或者点击链接时,浏览器进程会向渲染进程发送请求,渲染进程则会负责将网页内容下载并渲染到用户的屏幕上。一个浏览器窗口通常会有多个渲染进程,每个渲染进程独立运行,互不干扰。
- GPU 进程:负责处理浏览器中的 GPU 加速,它主要是为了加速图形渲染和 3D 动画效果。
- 插件进程:负责运行浏览器中的插件,如 Flash、Java 等。为了提高浏览器的安全性和稳定性,现代浏览器通常将插件运行在独立的进程中,以防止插件的崩溃或安全漏洞影响浏览器的整体稳定性和安全性。
- 扩展程序进程:负责运行浏览器中的扩展程序,如广告拦截器、翻译插件等。扩展程序运行在独立的进程中,从而保证浏览器的稳定性和安全性,避免扩展程序对浏览器的整体稳定性和安全性产生影响。
这些进程之间都是相互独立的,它们之间的通信通过浏览器进程进行协调和管理,从而保证了浏览器的稳定性和安全性,并能够更好地利用系统资源,提高浏览器的性能。
三、当你在浏览器输入内容时,浏览器内部做了什么?
简单来说UI线程会捕捉你的输入的内容:
- 如果是地址,UI线程启动一个网络线程来请求DNS进行域名解析,然后连接服务器获取数据,
- 如果是关键词:使用默认配置的搜索引擎来查询
更具体的是
- 解析输入的 URL:浏览器会将输入的 URL 解析成协议、主机名、路径等各个部分。
- 发送网络请求:浏览器会向解析出来的主机名发送网络请求,并且会将协议、主机名、路径等信息传递给网络层。
- DNS 解析:网络层会将主机名解析成对应的 IP 地址,并且在浏览器中建立一个 TCP 连接。
- 发送 HTTP 请求:浏览器会向服务器发送 HTTP 请求,包括请求方法(GET、POST、PUT 等)、请求头(User-Agent、Accept、Cookie 等)和请求体(如果是 POST 请求)等信息。
- 接收 HTTP 响应:服务器会对浏览器发送的请求进行处理,并返回 HTTP 响应,包括状态码、响应头(Content-Type、Content-Length 等)和响应体(HTML、CSS、JavaScript 等)等信息。
- 解析 HTML:浏览器会将接收到的 HTML 代码解析成 DOM 树,同时还会解析 CSS 和 JavaScript,生成 CSSOM 和 JavaScript 对象模型。
- 构建渲染树:浏览器会将 DOM 树和 CSSOM 合并成渲染树,渲染树只包含需要显示的内容,如可见的元素和文本等。
- 布局和绘制:浏览器会根据渲染树的布局信息计算每个元素的位置和大小,然后将其绘制到屏幕上。
- JavaScript 执行:如果 HTML 中包含 JavaScript 代码,则浏览器会执行这些代码,从而实现交互效果、动画效果等。
四、浏览器的渲染流程
1.使用safeBrowsing判断是否是恶意站点,safeBrowsing是谷歌内部站点安全系统
2.如果不是则访问服务器获取数据,网络线程告知UI线程数据准备完毕
3.UI线程会创建一个渲染器进程,浏览器进程将数据传递给渲染器进程,进入渲染流程
4.渲染器进程的任务就是把html,css,img等资源渲染成用户可交互的页面。
1.DOM树生成 – HTML的结构是什么样,有哪些节点,页面结构
1.生成流程
-
渲染器的主线程解析html构造DOM数据结构
-
tokeniser标记化
-
根据标记构造DOM树,创建document对象,向其中添加各种元素
2.DOM树的结构是什么样的?
DOM(Document Object Model)是一种基于树结构的数据模型,用于表示 HTML 或 XML 文档中的元素、属性和文本等内容。DOM 将整个文档看做一个树形结构,树的每个节点都代表文档中的一个元素、属性或文本节点。每个节点都有对应的属性和方法,可以通过 JavaScript 来访问和操作它们。
DOM 树的结构如下:
- Document:整个文档的根节点,包括 HTML 标签和文档声明等信息。
- Element:HTML 元素节点,如
<html>
、<body>
、<p>
等。 - Text:文本节点,如元素中的文本内容或属性值等。
- Comment:注释节点,如
<!-- 注释内容 -->
。 - Attribute:元素的属性节点,如
<a href="http://www.example.com">
中的href
属性。
DOM 树中的节点之间存在着父子关系和兄弟关系。每个节点都有自己的属性和方法,可以通过 JavaScript 代码来访问和操作它们。例如,可以使用 document.getElementById()
方法获取文档中的某个元素节点,或使用 element.setAttribute()
方法设置元素的属性值。同时,也可以通过 DOM 树中的节点来实现对 HTML 页面的动态操作和交互效果。
3.tokeniser标记化?
Tokeniser 标记化是 HTML 解析器将输入的 HTML 文本按照规则分割成不同类型的标记(token)的过程。HTML 标记包括开始标记、结束标记、自封闭标记、注释标记、字符引用标记等。
在标记化过程中,HTML 解析器会遵循 HTML 规范中定义的词法分析规则,将输入的 HTML 文本分割成一系列的标记。标记化过程主要包括以下几个步骤:
- 字符处理:读取输入流中的字符,逐个字符进行处理。
- 确定标记类型: 根据当前字符的类型,确定标记的类型,如开始标记、结束标记、自封闭标记、注释标记等。
- 解析标记中的属性:,如标记的名称、属性名和属性值等。
- 生成标记对象:根据标记的类型和属性,生成对应的标记对象。
- 放入标记队列中: 将生成的标记对象存储在标记队列中,等待进一步的处理。
在标记化过程中,HTML 解析器还会进行一些额外的处理,如处理字符实体引用、处理注释、处理文档类型声明等。所有这些处理都是为了最终生成一棵符合 HTML 规范的 DOM 树。
4.标记对象的结构是什么样的?
标记对象(Token)是在 HTML 解析过程中生成的一个对象,用于表示 HTML 文档中的不同类型的标记。在 HTML 中,标记主要包括开始标记、结束标记、自封闭标记、注释标记、字符引用标记等。不同类型的标记对象具有不同的属性和方法,可以通过 JavaScript 代码来访问和操作它们。
标记对象通常包含以下几个属性:
type
:标记的类型,如startTag
、endTag
、selfClosingTag
、comment
、doctype
等。name
:标记的名称,如标记的元素名称、注释内容等。attributes
:标记的属性列表,如元素的属性名和属性值等。selfClosing
:标记是否为自封闭标记。data
:标记的附加数据,如注释标记的注释内容、字符引用标记的实体名称等。startTag
和endTag
还包含selfClosingAcknowledged
属性,表示该标记是否被视为自封闭标记。
标记对象是 HTML 解析过程中的一个重要中间产物,通过标记化和解析标记,最终生成符合规范的 DOM 树,实现了浏览器对 HTML 文档的渲染和展示。
2.DOM树具体构建细节
-
创建一个 Document 对象作为根节点,并将它添加到文档中。
-
遍历标记对象,对于每个标记对象,根据它的类型和属性创建一个相应的节点,并将它添加到文档树中的合适位置。具体的添加方式如下:
-
对于开始标记,创建一个元素节点,并将它添加到父元素节点的子节点列表中。
-
对于结束标记,将父元素节点指向其祖先节点的父元素节点。
-
对于自封闭标记,创建一个元素节点,并将它添加到父元素节点的子节点列表中。
-
对于注释标记,创建一个注释节点,并将它添加到父元素节点的子节点列表中。
-
对于字符引用标记,创建一个文本节点,并将它添加到父元素节点的子节点列表中。
-
-
根据标记对象中的属性和文档树中节点的属性,建立节点之间的父子关系。具体的建立方式如下:
-
对于元素节点,将它的父节点指向它的直接父元素节点。
-
对于文本节点和注释节点,将它的父节点指向它的直接父元素节点。
-
通过上述步骤,可以根据 HTML 标记构建出 DOM 树。在 DOM 树中,每个节点都有一个类型(元素节点、文本节点等)、一个名称(元素节点的标签名、属性节点的属性名等)、一些属性(元素节点的属性、文本节点的文本内容等)和一些子节点(如果有的话)。DOM 树的结构反映了 HTML 文档中元素和它们之间的层次关系,便于通过 JavaScript 操作文档的内容和结构。
问题
-
图片和css不会阻塞html的解析: 因为不会影响DOM树的生成
由于图片和 CSS 文件不会影响 DOM 树的生成,所以浏览器不必等待它们的下载和解析,而是可以并行下载这些资源。这也就是为什么我们可以在 HTML 文档中同时引用多个 CSS 文件和图片,而不会阻塞 HTML 的解析和渲染。
需要注意的是,如果 CSS 文件中包含 @import 规则,那么浏览器会将它们当作外部 CSS 文件并等待它们的下载和解析,因为 @import 规则会影响到 CSSOM 树的生成。另外,如果 JavaScript 文件中包含 document.write() 方法,那么它会在 HTML 解析过程中动态生成新的 HTML 标记,可能会导致 HTML 解析阻塞。
-
如果遇到script标签则会停止html解析,去下载、解析、执行js,因为浏览器不知道这些js会不会影响当前的HTML结构。如果改变了,那之前的解析就没用了
3.计算样式:每个节点长什么样:元素大小、形状
1.CSSOM树
DOM树创建的过程中当遇到一个链接或者样式表的时候会CSSOM树
CSSOM 树是在文档加载过程中被创建的,它是一棵由浏览器解析样式表并计算出每个选择器的具体样式所组成的树状结构。浏览器通过以下步骤来创建 CSSOM 树:
- 解析 CSS 文件:当浏览器遇到一个链接或嵌入的样式表时,它会开始下载 CSS 文件并将其解析为一组样式规则。
- 构建样式规则:浏览器会将解析出来的样式规则存储在内存中,并将它们转换为一棵树状结构,称为样式规则树。
- 计算选择器的优先级:当一个元素需要应用一个样式时,浏览器需要计算出所有匹配该元素的选择器的优先级,并决定应用哪个样式规则。
- 生成 CSSOM 树:最后,浏览器将计算出的每个元素的最终样式,以及它们的父子关系和层级关系等信息,组成一棵称为 CSSOM 树的树状结构。
CSSOM 树通常是在 DOM 树之后被创建的,因为它需要等待所有样式表都被下载和解析完毕。然而,如果浏览器在加载样式表时遇到了无法解析的语法错误,那么它可能会在构建 CSSOM 树时遇到问题,并导致一些样式规则无法生效。
2.样式计算
主线程解析css,确定DOM节点的计算样式,没有提供自己写的,浏览器也有自己的默认样式
计算样式(也称为样式计算、样式解析)是指浏览器根据 DOM 树和 CSSOM 树计算出每个元素的最终样式的过程。以下是计算样式的具体实现细节:
- 样式匹配:对于每个元素,浏览器需要找到所有适用于它的 CSS 规则。这个过程称为样式匹配,它的目标是找到一个元素所适用的所有样式规则。
- 属性继承:如果某个元素没有设置某个属性的值,那么浏览器会从它的父元素继承该属性的值。这个过程称为属性继承。
- 属性计算:浏览器将匹配到的样式规则应用到元素上,计算出每个属性的最终值。这个过程可能涉及到一些复杂的计算,例如对于 font-size 属性,浏览器需要将相对单位(如 em 和 %)转换为绝对单位(如 px),才能得到最终的像素值。
- 层叠与排序:当多个样式规则同时适用于一个元素时,浏览器需要根据层叠规则(如优先级、特殊性等)来决定哪个样式规则应该被应用。这个过程称为层叠与排序。
- 最终样式的生成:经过样式匹配、属性继承、属性计算和层叠与排序后,浏览器可以得到每个元素的最终样式,并将其保存在元素的 RenderStyle 对象中。最终样式包含了所有计算出来的属性值,例如 font-size、background-color、border-radius 等。
需要注意的是,样式计算是一个相对耗时的过程,因为它需要遍历整个 DOM 树和 CSSOM 树,并进行复杂的计算和比较。为了提高性能,现代浏览器会采用一些优化措施,例如缓存计算结果、使用静态分析技术等。
4.layout Tree构造: 节点放哪,占多大位置: 元素大小、形状、位置
知道每个节点的结构和样式后,我们需要知道每个节点需要放在哪个位置,就是节点的坐标和每个节点需要占据多大的区域
layout上的节点,每个节点都记录的x,y坐标和边框尺寸
1.为什么样式计算的过程中就已经能够知道元素的大小了,layout tree中还需要计算
在 CSS 样式计算的过程中,可以确定元素的大小,但是这个大小只是一个初始的估计值,因为在实际的渲染过程中,元素的大小可能会受到许多其他因素的影响,比如内容的长度、元素的位置、盒模型的计算方式等。
实际上,在布局计算(Layout)的过程中,会根据元素的实际内容、样式以及文档流中的位置等因素,重新计算元素的大小。比如,如果元素中包含了可变长度的文本,那么它的大小就不能在样式计算时确定,只有在实际布局计算时才能确定。此外,元素的大小还受到 padding、border、margin 等样式的影响,这些样式的计算也需要在布局计算时进行。因此,布局计算是非常重要的一步,它可以确定元素最终的大小和位置,从而使得渲染树中的元素框可以正确地显示在页面上。
2.layout Tree的构建
在浏览器的渲染过程中,HTML 元素的大小和位置是由其在文档流中的位置以及应用的样式所决定的。在样式计算之后,浏览器会生成一棵渲染树(或布局树或排版树,通常称为 Layout Tree),它是由 DOM 树中可见的、需要显示在页面上的元素和它们的样式属性构成的。每个元素在渲染树中都对应着一个或多个矩形框(Box),这些矩形框描述了元素在屏幕上所占的位置和大小。
渲染树的构建过程包括以下几个步骤:
- 从根节点开始遍历 DOM 树中的所有可见节点。
- 对于每个可见节点,判断它是否需要在渲染树中生成对应的元素框(Box)。有些节点,比如
<script>
或者隐藏的节点,不会被渲染,因此不会生成元素框。 - 如果需要生成元素框,则计算出该节点在渲染树中对应的元素框的位置、大小、边距、边框和填充等属性。这个过程被称为布局计算(Layout)。
- 如果该节点有子节点,则递归处理其所有子节点,直到所有可见节点都处理完毕。
在布局计算的过程中,浏览器会根据盒模型、定位、浮动等 CSS 属性计算出每个元素框的位置和大小,并考虑到文档流中元素的相对位置、层叠规则和其他一些特殊情况。布局计算的结果被保存在元素框的 LayoutObject 中,它包含了元素的位置、大小、边距、边框、填充以及其他的一些属性。这些 LayoutObject 最终组成了渲染树中的所有元素框。
注意: DOM tree和layout Tree不是一一对应的,设置了display:none的节点不会出现在layout Tree上,因为DOM树不关注样式,但是layout Tree是DOM树和样式计算生成的,和页面上的节点是一一对应的
4.绘制(paint)阶段 – 创建绘制记录表-绘制顺序
知道了页面的大小、形状、位置还不够,还需要知道绘制顺序,比如z-index会影响层级,如果按照DOM的层级结构来渲染就会导致错误渲染
主线程遍历layout tree创建绘制记录表,记录绘制顺序
在绘制(Paint)阶段中,浏览器会遍历渲染树中的每个可见节点,并将其绘制到屏幕上。具体来说,绘制过程会根据每个可见节点的盒模型(Box Model)信息,生成一系列绘制记录(Paint Record),这些记录会被存储在绘制记录表中,以便后续的绘制操作使用。
绘制记录表(Paint Record Table)是一个数据结构,用于存储绘制记录,通常由一个或多个位图(Bitmap)组成。每个绘制记录通常包含以下信息:
- 绘制类型(Paint Type):表示该记录是一个普通的绘制记录,还是一个特殊类型的绘制记录(如清空屏幕、重置裁剪区等)。
- 绘制范围(Paint Area):表示该绘制记录需要绘制的区域,通常是一个矩形。
- 绘制样式(Paint Style):表示该绘制记录的颜色、渐变、边框等绘制样式信息。
创建绘制记录表的过程通常包括以下几个步骤:
- 初始化位图:创建一个或多个位图,用于存储绘制记录。位图通常是一个二维数组,每个元素对应屏幕上的一个像素。
- 遍历渲染树:从根节点开始遍历渲染树,对于每个可见节点,生成相应的绘制记录。
- 合并绘制记录:对于一些相邻的、具有相同样式的绘制记录,可以将它们合并成一个更大的绘制记录,从而减少绘制的次数,提高性能。
- 存储绘制记录:将生成的绘制记录存储到绘制记录表中,以便后续的绘制操作使用。
例子:
<!DOCTYPE html>
<html>
<head>
<style>
.square {
width: 100px;
height: 100px;
background-color: red;
}
.circle {
width: 100px;
height: 100px;
background-color: blue;
border-radius: 50%;
}
</style>
</head>
<body>
<div class="square"></div>
<div class="circle"></div>
</body>
</html>
在绘制阶段,浏览器会根据Layout Tree中的每个元素的绘制记录表来绘制页面。对于上面的示例,浏览器可能会创建如下绘制记录表:
元素 | 绘制指令 |
---|---|
.square |
绘制一个红色的矩形,左上角坐标为(0, 0),宽度为100px,高度为100px |
.circle |
绘制一个蓝色的圆形,中心坐标为(100px, 50px),半径为50px |
浏览器会按照绘制记录表中的顺序来绘制页面,最终呈现给用户的就是这些绘制指令所描述的图形。
5.栅格化 – 转换信息为像素点展示到页面
栅格化(Rasterization)是指将页面中的矢量图形(如文字、形状、线条等)转换成像素图形的过程。在渲染引擎中,栅格化通常是发生在绘制阶段的最后一步。
栅格化的流程一般如下:
- 将绘制记录表中的绘制指令按照顺序依次执行,将每个元素绘制到对应的图层上。
- 对于每个图层,浏览器会将其内容分割成一系列小的矩形区域,称为“图块”(Tile)。
- 对于每个图块,浏览器会将其转换成一个像素图形,称为“栅格化图块”(Raster Tile)。
- 栅格化图块的大小通常是根据屏幕分辨率和图层大小来确定的。
- 对于每个栅格化图块,浏览器会根据图层上的内容生成对应的像素图形,包括文字、图片、形状等。
- 浏览器会将所有的栅格化图块组合起来,生成最终的像素图形,将其显示在屏幕上。
- 早期: 只栅格化可视区域,滚动栅格其他的,展示延迟
- 现在: 新的栅格化流程,合成,将页面的各个部分进行分层,然后分别对其栅格化,并在合成器线程中单独进行合成,就是页面所有元素按照某种规则进行分图层,并把图层都栅格化好了,只需要把可视区的内容组合成一帧。
需要注意的是,栅格化的过程中,由于矢量图形和像素图形之间存在差异,因此会有一定的误差和损失。为了尽量减少这种误差和损失,渲染引擎通常会使用一些技术,如抗锯齿(Anti-aliasing)和像素对齐(Pixel Alignment)等。
6.layer tree
主线程遍历layout tree生成layer tree绘制顺序确定后,主线程将信息传递给合成器线程。合成器线程将每个图层栅格化,由于一层可能像页面的长度一样大,所以合成器线程将图层分为很多图块,将每个图块发送给栅格化线程,栅格化线程栅格每个图块,将其储存在GPU中,合成器线程搜集图块信息,里面记录的图块在内存中的位置,和在页面的那个位置绘制图块。根据这些信息合成器线程生成一个合成器帧,通过ipc传递给浏览器进程,浏览器进程将合成器帧传递到GPU,渲染到平面上。滚动页面生成新的合成器帧,再渲染
7.为什么已经有了layout Tree还要layer Tree
虽然Layout Tree可以用来描述网页的布局和结构,但是在绘制阶段,浏览器还需要考虑到一些性能和效率方面的问题。
比如,如果一个页面中有很多复杂的元素,那么在进行绘制的时候,浏览器需要逐个遍历这些元素,并且对于每一个元素都要执行一遍绘制指令。这样一来,绘制时间就会变得非常长,从而导致页面的性能下降。
为了解决这个问题,浏览器引入了Layer Tree的概念。Layer Tree是指一种抽象的树状结构,它将网页中的元素按照一定的规则分成不同的层,并且为每一层都创建一个独立的绘制上下文。
这样一来,在绘制阶段,浏览器就可以按照Layer Tree中的层次结构来绘制页面,而不需要逐个遍历每个元素。同时,由于每个层都有自己的绘制上下文,所以浏览器可以在绘制一个层时,直接将整个层的绘制结果缓存下来,以便后续的重绘操作。
因此,Layer Tree的出现,可以极大地提高网页的绘制效率和性能。
例子:
以下是一个简单的Layer Tree示例:
假设有一个HTML文档,其中包含一个id为container
的div
元素,它的样式如下:
#container {
position: relative;
width: 500px;
height: 500px;
background-color: #f00;
}
在这个例子中,渲染引擎会创建一个Layer Tree,其中会包含一个根图层和一个子图层,具体如下:
- 根图层:表示整个文档的内容,它的大小通常是整个文档的大小,也就是浏览器窗口的大小。在这个例子中,根图层的大小为浏览器窗口的大小。
- 子图层:表示id为
container
的div
元素。在这个例子中,子图层的大小是根据div
元素的大小计算出来的。
这样,渲染引擎就可以将每个图层独立地进行处理和绘制,从而提高了渲染性能。同时,由于每个图层都可以独立地进行变换、透明度等操作,因此还可以实现一些比较复杂的效果,如平移、缩放、旋转等。
五、总结流程
网络线程获取到数据后,传递给渲染器进程的主线程
-
构建DOM树
-
样式计算style
-
根据DOM树和样式计算生成layout tree
-
遍历layout tree生成绘制顺序表paint
-
然后遍历layout tree生成layer tree
-
主线程将layer tree 和绘制顺序表传递给合成器线程。
合成器线程进行分图层,并把图层分成更小的图块传递给栅格化线程, -
栅格完成后合成器线程会接收到栅格化线程返回的图块信息
-
合成器线程生成一个合成器帧,将合成器帧通过ipc管道传回给浏览器进程,
浏览器进程再传递给GPU进程进行渲染
1.重排
重排(reflow)是指当页面中的某些元素的尺寸、位置等属性发生变化时,浏览器需要重新计算这些元素的几何属性(如宽、高、位置等),并且根据这些计算结果重新布局页面,这个过程就叫做重排。
重排会导致页面重新渲染,因此会比较耗费性能。而且,重排往往会引发重绘(repaint)的过程,即重新绘制页面的各个部分。因此,减少重排的次数是优化页面性能的一个重要手段。
以下是一些常见的会引起重排的操作:
- 改变窗口大小
- 改变字体大小
- 改变元素的位置、尺寸、边距、边框等属性
- 内容的改变,例如用户在表单中输入文本、图片加载完成等
- 添加或删除元素
为了减少重排的次数,可以采取以下几个措施:
- 尽量避免频繁的操作DOM,因为DOM的操作往往会引发重排
- 将需要操作的元素缓存起来,避免重复计算
- 通过CSS的transform属性来实现元素的平移、缩放、旋转等操作,因为这些操作不会影响到元素的布局,因此不会引起重排
- 使用CSS的position属性将元素定位到页面的固定位置,避免元素位置的改变引发重排
2.重绘
重绘(Repaint)指的是当页面上的某个元素样式发生改变时,浏览器会重新绘制该元素的内容,使其展示新的样式。但是,元素的位置和大小等布局信息并没有改变,所以不需要重新计算布局。
在重绘过程中,浏览器会根据元素的样式属性生成新的绘制记录表(Paint Records),然后使用该记录表重新绘制元素的内容。重绘是一个相对较快的操作,因为它只需要重新绘制元素的内容,而不需要重新计算布局。
需要注意的是,虽然重绘的代价相对较小,但是如果页面上的元素频繁重绘,会对浏览器的性能产生一定的影响。因此,在编写页面时应尽量减少不必要的重绘操作。
3.为什么改变样式不会重排,layout tree不是根据cssom树和DOM生成的吗?
实际上,当样式改变时,需要重新计算样式和布局信息,而这些计算都是由浏览器内部的渲染引擎完成的。重绘和重排都是由渲染引擎触发和执行的。
具体来说,当样式改变时,浏览器会重新计算 CSSOM 树 和 Layout Tree,以确定元素在页面上的布局和渲染。但是,由于浏览器的优化机制,它会尽量减少重排和重绘的次数,以提高渲染效率。
在样式改变的情况下,如果仅仅是颜色或者字体等对布局无影响的样式属性发生了改变,浏览器会直接对已经计算好的 Layout Tree 进行重绘,而不必重新计算布局信息。这是因为这些样式属性不会影响元素在文档流中的位置和大小,所以不需要重新计算布局。
但是,如果样式改变导致了元素的位置和大小发生变化,就需要重新计算布局信息,并重新生成 Layout Tree 和 Paint Tree,最终重新绘制页面。这个过程就是重排和重绘的过程。
预告:本专栏下一篇js执行原理
原文链接:https://juejin.cn/post/7214400156593406011 作者:可神明在说谎