浏览器渲染原理与过程

要了解这个过程,我们首先得知道一个名词——关键路径渲染(Critical Rendering Path,它是指与当前用户操作有关的内容。例如用户在浏览器中打开一个页面,其中页面所显示的东西就是当前用户操作相关的内容,也就是浏览器从服务器那里收到的HTML、css、JavaScript等相关资源,然后经过一系列处理后渲染出的web页面。

1.浏览器渲染过程

先解释一下几个概念:
DOM Tree:浏览器将HTML解析成树形的数据结构。
CSS Rule Tree:浏览器将CSS解析成树形的数据结构。
Render Tree: DOM和CSSOM合并后生成Render Tree。
Layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。
Display: 按照算出来的规则,通过显卡,把内容画到屏幕上。
浏览器渲染过程

  1. 处理HTML标记并构建DOM树
  2. 处理css标记并构建CSSOM树
  3. 将DOM树和CSSOM树合并构建一个渲染树
  4. 渲染树布局,浏览器通过Render Tree计算出每个节点对象在页面的确切大小和位置
  5. 渲染树绘制,浏览器会调用渲染器的paint()方法在屏幕上显示内容
2. 阻塞渲染

我们知道,现代浏览器总是并行加载资源,例如当HTML解析器被脚本阻塞时,解析器虽然会停止构建DOM树,但仍然会辨识该脚本后面的资源,并进行预加载。
对于css阻塞渲染

css的加载并不会导致HTML解析和渲染的停止,但是会影响到js脚本的执行,因为js脚本不仅可以修改DOM,也可以读取修改CSSOM,所以在js脚本执行前,浏览器必须保证CSS文件完全加载并解析完成,即CSSOM树完全构建好。这就导致了js执行的延迟,渲染延迟。(这就是css阻塞js执行,阻塞渲染的根本原因)

有一些解决办法:

  1. 对css进行精简并尽快提供
  2. 可以用媒体类型(会加载不会阻塞)
  3. 用媒体查询(会加载,只有在符合的设备上才会进行阻塞)

另外:
(1). 当浏览器遇到一个script 标记时,DOM 构建将暂停,直至脚本完成执行;
(2). JavaScript 可以查询和修改 DOM 与 CSSOM;
(3). CSSOM 构建时,JavaScript 执行将暂停,直至 CSSOM 就绪。
所以script 标签的放置位置很重要,可以遵循以下原则:

  1. 在引入顺序上,CSS 资源先于 JavaScript 资源
  2. JavaScript 应尽量少影响 DOM 的构建

对于js阻塞,有两种解决方法(对于inline-script无效):
defer属性<script src="" defer></script>
这是延迟执行引入的js脚本(即脚本加载是不会导致解析停止,等到document全部解析完毕后,defer-script也加载完毕后,在执行所有的defer-script加载的js代码,再触发Domcontentloaded)
async属性<script src="" async></script>
(1)这是异步执行引入的js脚本文件
(2)与defer的区别是async会在加载完成后就执行,但是不会影响阻塞到解析和渲染。但是还是会阻塞load事件,所以async-script会可能在DOMcontentloaded触发前或后执行,但是一定会在load事件前触发。


3. 改变阻塞渲染

对于CSS:
对应于上文中提到的解决办法,除了对css进行精简并尽快提供外,其他进行如下示例

<link href="index.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 30em) and (orientation: landscape)">
  • 第一个资源会加载并阻塞
  • 第二个设置了媒体类型,会加载但不会阻塞,print声明只在打印网页时使用
  • 第三个资源提供了媒体查询,会在符合条件时阻塞渲染

**js: **
defer

<script src='app1.js' defer></script>
<script src='app2.js' defer></script>
<script src='app3.js' defer></script>

defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时HTML 并未停止解析,这两个过程是并行的。整个 document 解析完毕且 defer-script 也加载完成之后(这两件事情的顺序无关),会执行所有由 defer-script 加载 JavaScript 代码,然后触发 DOMContentLoaded 事件。
defer 不会改变 script 中代码的执行顺序,示例代码会按照1、2、3的顺序执行。所以,defer 与普通 script 相比,有两点区别:

  • 载入 JavaScript 文件时不阻塞 HTML 的解析
  • 执行阶段被放到 HTML 标签解析完成之后

async

<script src='app.js' async></script>
<script src='ad.js' async></script>
<script src='statistics.js' async></script>

async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行——无论此刻是 HTML 解析阶段还是 DOMContentLoaded 触发之后。需要注意的是,这种方法加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发之前或之后执行,但一定在 load 触发之前执行。

从上一段也能推出,多个 async-script 的执行顺序是不确定的。
值得注意的是,向 document 动态添加 script 标签时,async 属性默认是 true,也就是使用 document.createElement创建的 script 默认是异步的,如果想要同步执行,必须手动设置属性值为false。

console.log(document.createElement("script").async);  // true

https://www.jianshu.com/p/e53141edca6d
https://www.cnblogs.com/slly/p/6640761.html
https://www.imooc.com/article/40004

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值