浏览器如何渲染网页
首先我们要了解一个名词——关键渲染路劲。关键渲染路径是指浏览器从最初接收请求来的HTML、CSS、javascript等资源,然后解析、构建树、渲染布局、绘制,最后呈现给客户能看到的界面这整个过程。
用户看到页面实际上可以分为两个阶段:页面内容加载完成和页面资源加载完成,分别对应于DOMContentLoaded
和Load
。
DOMContentLoaded
事件触发时,仅当DOM加载完成,不包括样式表,图片等load
事件触发时,页面上所有的DOM,样式表,脚本,图片都已加载完成
浏览器渲染的过程主要包括以下五步:
- 浏览器将获取的HTML文档解析成DOM树。
- 处理CSS标记,构成层叠样式表模型CSSOM(CSS Object Model)。
- 将DOM和CSSOM合并为渲染树(
rendering tree
)将会被创建,代表一系列将被渲染的对象。 - 渲染树的每个元素包含的内容都是计算过的,它被称之为布局
layout
。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。 - 将渲染树的各个节点绘制到屏幕上,这一步被称为绘制
painting
。
webkit渲染引擎流程
浏览器接收到 HTML 文件并转换为 DOM 树
当我们打开一个网页时,浏览器都会去请求对应的 HTML 文件。虽然平时我们写代码时都会分为 JS、CSS、HTML 文件,也就是字符串,但是计算机硬件是不理解这些字符串的,所以在网络中传输的内容其实都是 0
和 1
这些字节数据。当浏览器接收到这些字节数据以后,它会将这些字节数据转换为字符串,也就是我们写的代码。
当数据转换为字符串以后,浏览器会先将这些字符串通过词法分析转换为标记(token),这一过程在词法分析中叫做标记化(tokenization)。
那么什么是标记呢?这其实属于编译原理这一块的内容了。简单来说,标记还是字符串,是构成代码的最小单位。这一过程会将代码分拆成一块块,并给这些内容打上标记,便于理解这些最小单位的代码是什么意思。
当结束标记化后,这些标记会紧接着转换为 Node,最后这些 Node 会根据不同 Node 之前的联系构建为一颗 DOM 树
当然,在解析 HTML 文件的时候,浏览器还会遇到 CSS 和 JS 文件,这时候浏览器也会去下载并解析这些文件,注意以下几点:
- DOM树在构建的过程中可能会被CSS和JS的加载而执行阻塞
display:none
的元素也会在DOM树中- 注释也会在DOM树中
script
标签会在DOM树中- 当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
将 CSS 文件转换为 CSSOM 树
其实转换 CSS 到 CSSOM 树的过程和DOM树的构建过程是极其类似的
在这一过程中,浏览器会确定每一个节点的样式到底是什么,并且这一过程是很消耗资源的。因为样式你可以自行设置给某个节点,也可以通过继承获得。在这一过程中,浏览器得递归 CSSOM 树,然后确定具体的元素到底是什么样式。每个CSS文件都被分析成一个StyleSheet对象,每个对象都包含CSS规则。CSS规则对象包含对应于CSS语法的选择器和声明对象以及其他对象。
在这个过程需要注意的是:
- CSS解析可以与DOM解析同时进行。
- CSS解析与
script
的执行互斥 。 - 在Webkit内核中进行了
script
执行优化,只有在JS访问CSS时才会发生互斥。
生成渲染树
当我们生成 DOM 树和 CSSOM 树以后,就需要将这两棵树组合为渲染树。
在这一过程中,不是简单的将两者合并就行了。渲染树只会包括需要显示的节点和这些节点的样式信息,如果某个节点是 display: none
的,那么就不会在渲染树中显示。
渲染树生成后,还是没有办法渲染到屏幕上,渲染到屏幕需要得到各个节点的位置信息,这就需要布局(Layout)的处理了。
渲染树布局(layout of the render tree)
布局阶段会从渲染树的根节点开始遍历,由于渲染树的每个节点都是一个Render Object对象,包含宽高,位置,背景色等样式信息。所以浏览器就可以通过这些样式信息来确定每个节点对象在页面上的确切大小和位置,布局阶段的输出就是我们常说的盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。需要注意的是:
float
元素,absoulte
元素,fixed
元素会发生位置偏移。- 我们常说的脱离文档流,其实就是脱离Render Tree。
渲染树绘制(Painting the render tree)
布局完成后,调用 GPU 绘制,浏览器会遍历渲染树,调用渲染器的paint()
方法合成图层,显示在屏幕上。
浏览器渲染网页的那些事儿
浏览器主要组件结构
Firefox使用Geoko,Mozilla自主研发的渲染引擎。Safari和Chrome都使用webkit。Webkit是一款开源渲染引擎,它本来是为linux平台研发的,后来由Apple移植到Mac及Windows上。
虽然主流浏览器渲染过程叫法有区别,但是主要流程还是相同的。
为什么操作DOM慢?
因为DOM是属于渲染引擎内的东西,而JS又是JS引擎中的东西。当我们通过JS操作DOM的时候,其实这个操作涉及到了两个线程之间的通信,那么势必会带来一些性能上的消耗。操作DOM次数一多,也就等同于一直在进行线程之间的通信,并且操作DOM可能会带来重绘回流的情况,所以也就导致了性能上的问题。
什么情况下会阻塞渲染?
首先渲染的前提是生成渲染树,所以HTML和CSS肯定会阻塞渲染。如果想渲染的更快,就应该降低一开始需要渲染的文件大小,并且扁平层级,优化选择器。
当浏览器解析到script标签时,会暂停构建DOM,完成后才会从暂停的地方重新开始。也就是说,想首屏渲染的越快,就越不应该在首屏就加载JS文件,这也是建议将script标签放在body标签底部的原因。不过,在当下,可以给script标签添加defer或者async属性。
当script标签加上defer属性后,表示该JS文件会并行下载,但是会放到HTML解析完成后顺序执行,所以对于这种情况可以把script标签放在任意位置。
对于没有任何依赖的JS文件可以加上async属性,表示JS文件下载和解析都不会阻塞渲染。