详解浏览渲染原理

我们都知道JS有一个JS引擎,那么执行渲染也有一个渲染引擎,同样,渲染引擎在不同的浏览器中也是不同的。

浏览器接收到HTML文件并转换成DOM树

当我们打开一个网页时,浏览器都会去请求对应的html文件,虽然平时我们写代码的时候都会分为HTML、CSS、JS文件,也就是字符串,但是计算机硬件不理解这些字符串,所以在网络中传输的内容都是0和1这些字节数据。当浏览器接收到这些字节数据以后,它会将字节数据转换为字符串,也就是我们写的代码。
在这里插入图片描述
当数据转换成字符串以后,浏览器会先将这些字符串通过词法分析转换成标记,这一过程在词法分析中叫做标记化
在这里插入图片描述
那么什么是标记呢?这其实属于编译原理这一块内容,简单来说,标记还是字符串,是构成代码的最小单位。这一过程会将代码分拆成一块块,并给这些内容打上标记,便于理解这些最小单位的代码是什么意思。
在这里插入图片描述
当结束标记化之后,这些标记会紧接着转换为Node,最后这些Node会根据不同的Node之前的联系构建一颗DOM树。
在这里插入图片描述
以上就是浏览器从网络中收到HTML文件并且转换的一系列过程
在这里插入图片描述
当然,在解析HTML文件的时候,浏览器海域遇到CSS和JS文件,这时候浏览器也会下载并解析这些文件,接下来我们学习浏览器如何解析CSS文件

将CSS文件转换成CSSOM树

其实转换CSS到CSSOM树的过程和上一小节过程类似
在这里插入图片描述
在这一过程中,浏览器会确定下每一个节点的样式到底是什么,并且这一过程其实是很消耗资源的,因为样式可以自行设置给某个节点,也可以通过继承获得。在这一过程中,浏览器的递归CSSOM树,然后确定具体的元素到底是什么样式。

如果你有点不理解为什么会消耗资源的话,我这里举个例子

<div>
  <a> <span></span> </a>
</div>
<style>
  span {
    color: red;
  }
  div > a > span {
    color: red;
  }
</style>

对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的 span 标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的 span 标签,然后找到 span 标签上的 a 标签,最后再去找到 div 标签,然后给符合这种条件的 span 标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平

生成渲染树

当我们生成 DOM 树和 CSSOM 树以后,就需要将这两棵树组合为渲染树。
在这里插入图片描述
在这一过程中,不是简单的将两者合并就行了。渲染树只会包括需要显示的节点和这些节点的样式信息,如果某个节点是display:none的,那么就不会再渲染树中显示。

当浏览器生成渲染树之后,就会根据渲染树来进行布局(也可以叫做重排),然后调用GPU绘制,合成图层,显示在屏幕上。

那么通过以上内容,我们已经详细的了解到了浏览器从接收文件到将文件内容渲染在屏幕上这一个过程。接下来我们将会学习上半部分遗留下来的知识点

为什么操作DOM慢

想必大家都听过操作 DOM 性能很差,但是这其中的原因是什么呢?

因为DOM是属于渲染引擎中的东西,而JS又是JS引擎中的东西。当我们通过JS操作DOM的时候,其实这个操作涉及到了两个线程之间的通信,那么势必会带来一些性能上的损耗。操作DOM次数一多,也就等同于一直在进行线程之间的通信,并且操作DOM可能还会带来重绘重排的情况,所以就导致了性能问题。

经典面试题:插入几万个DOM,如何实现页面不卡顿?

对于这道题目来说,首先我们肯定不能一次性把几万个 DOM 全部插入,这样肯定会造成卡顿,所以解决问题的重点应该是如何分批次部分渲染 DOM。大部分人应该可以想到通过 requestAnimationFrame 的方式去循环的插入 DOM,其实还有种方式去解决这个问题:虚拟滚动(virtualized scroller)。

这种技术的原理就是只渲染可视区域内的内容,非可见区域的那就完全不渲染了,当用户在滚动的时候就实时去替换渲染的内容。

在这里插入图片描述
从上图中我们可以发现,即使列表很长,但是渲染的 DOM 元素永远只有那么几个,当我们滚动页面的时候就会实时去更新 DOM,这个技术就能顺利解决这道经典面试题。

什么情况阻塞渲染

首先渲染的前提是生成渲染树,所以 HTML 和 CSS 肯定会阻塞渲染。如果你想渲染的越快,你越应该降低一开始需要渲染的文件大小,并且扁平层级,优化选择器

然后当浏览器在解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。

当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性。

当 script 标签加上 defer 属性以后,表示该 JS 文件会并行下载,但是会放到 HTML 解析完成后顺序执行,所以对于这种情况你可以把 script 标签放在任意位置。

对于没有任何依赖的 JS 文件可以加上 async 属性,表示 JS 文件下载和解析不会阻塞渲染。

什么是DOCTYPE以及作用?

DTD文档类型定义是一系列的语法规则,又来定义XML或者HTML的文件类型,浏览器会使用它来判断问的那个类型,决定使用何种协议来解析以及切换浏览器模式,也就是说告诉浏览器文档是什么类型,

DOCTYPE就是用来声明文档类型和DTD规范的,一个主要的用途便是文件的合法性验证,如果文件代码不合法,那么浏览器解析时便会出一些差错,也就是说告诉浏览器包含了哪个DTD

DOCTYPE类型:

H5:

4.0有一个严格模式
该DTD包含了所有html元素和属性,但不包括展示性和弃用的元素

4.1有一个传统模式
该DTD包含了所有html元素和属性,包括展示性和弃用的元素

浏览器渲染过程
浏览器拿到html经过html parser转换成DOM Tree,拿到css后按照css规则和css parser解释器转成CSSOM tree,最后DOM tree和CSSOM tree通过attachment整合就形成Render tree,这里基本上渲染的结构就出来了,在layout之前Render tree不知道html的具体位置,比如不知道div具体在那个位置,通过layout就能精确的计算出DOM的位置、颜色、宽高,Paint根据GPU开始画图从而展示出来
在这里插入图片描述

DOM tree:
在html解析后,解析器会把解析完成的结果转换成DOM对象,在进一步构建DOM树
在这里插入图片描述

CSSOM tree:
CSS下载完成之后对css进行解析,解析成css对象,然后把对象组装起来,构建CSSOM树
在这里插入图片描述

Render tree:
当DOM树和CSSOM树都创建完成之后,浏览器根据这两个树构建一棵渲染树

重排reflow

DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该出现的位置,这个过程叫做reflow。

什么时候触发reflow

  1. 当你增加、删除、修改DOM节点的时候,会导致Reflow或Repaint,DOM树和Render树改变了所以会导致repaint
  2. 当你移动DOM的位置,或者是搞个动画的时候
  3. 当你修改css样式的时候
  4. 当你resize窗口的时候(移动端没有这个问题),或者是滚动的时候
  5. 当你修改网页默认字体的时候

重绘repaint

定义:
当各种盒子的位置,大小以及其他属性例如颜色、字体大小都确定下来之后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是内容就出现了,这个过程叫做repaint

减少重绘和重排

  1. 使用transform替换top
<div class="test"></div>
<style>
  .test {
    position: absolute;
    top: 10px;
    width: 100px;
    height: 100px;
    background: red;
  }
</style>
<script>
  setTimeout(() => {
    // 引起回流
    document.querySelector('.test').style.top = '100px'
  }, 1000)
</script>
  1. 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发重排(改变了布局)
  2. 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
  3. 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
  4. CSS 选择符从右往左匹配查找,避免节点层级过多
  5. 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值