likes
comments
collection
share

你真的了解浏览器的渲染原理吗?

作者站长头像
站长
· 阅读数 8

一、前言

二、解析渲染是什么

有一个场景你一定不陌生,你从浏览器的地址栏中输入了一个URL,回车之后,很快你就能看到了一个页面。那这个过程总的来说可以分为两步:

  • 资源请求获取
  • 解析渲染

它们的关系是这样的:

你真的了解浏览器的渲染原理吗?

网络线程会去请求HTML文档,请求到之后会产生一个渲染的任务并加入到消息队列中,在事件循环的机制下,渲染主线程会从消息队列中取出渲染任务去执行,这时就开启了解析渲染的过程。解析渲染就是将资源请求获取到的HTML字符串最后变成可见的像素信息。

这个字符串里面包含了CSS,JS信息,因为CSS,JS都是被引入到HTML中的,如何把这些信息最后变成像素信息输出,这就是解析渲染过程。

三、解析渲染过程

你真的了解浏览器的渲染原理吗?

1、解析HTML-Parse

(1)构建出DOM树

深度遍历DOM节点,目的是把所有DOM节点变成一个JS对象,使得JS可以去操作DOM。

你真的了解浏览器的渲染原理吗?

(2)构建CSSOM

把包含的所有的CSS转化成CSSOM树,目的同样是把所有的CSS变成一个对象,使JS可以去操作。HTML中的CSS可能包含以下几种类型:

  • <style> 内部样式表
  • <link> 外部样式表
  • <div style=""> 行内样式
  • 浏览器默认样式表

经过转化后,每一种类型都是一个对象,随便打开一个页面,控制台可以查看所有样式对象化后的结果:

你真的了解浏览器的渲染原理吗?

具体是怎么转化的:

你真的了解浏览器的渲染原理吗?

(3)CSS,JS资源请求

HTML解析过程会构建DOM树和CSSOM树,那这个过程是怎么样的呢?

你真的了解浏览器的渲染原理吗?

渲染主线程在解析HTML过程中,为了提高效率,会同时启动一个预解析线程,目的是让预解析线程率先把HTML包含的外部的CSS,JS文件下载。

如果主线程遇到link位置,此时外部的CSS文件还没有下载解析好,主线程不会等待,继续解析后续的HTML。如果后面预解析线程解析好了CSS,把结果交给主线程,主线程转化成CSSOM。由于下载和解析CSS的工作是在预解析线程中进行的,因此CSS不会阻塞HTML的解析。

你真的了解浏览器的渲染原理吗?

如果主线程解析遇到script位置,会停止解析HTML,等待JS文件,并将全局代码解析执行完成后,才能继续解析HTML。因为JS代码执行过程中可能会修改当前的DOM树,所以DOM树的生成必须要暂停,因此JS的执行会阻塞HTML的解析。

如果JS执行过程中,有引用CSS文件的,此时CSS还没有下载好,此时JS执行又会阻塞,必须等CSS都下载好了才会继续执行。

基于这个原因,在实际的开发中,CSS的引入放在HTML的head中,JS脚本代码放在HTML尾部,可以很大程度避免因为引入资源的位置不当导致首次渲染时间过长。

2、样式计算-Style

主线程会遍历得到的DOM树,依次为树中的每个节点计算出它最终的样式,Computed Style。这个过程会得到一棵带有样式的DOM树。

3、布局-Layout

依次遍历DOM树的每一个节点,计算每个节点的几何信息。例如节点的宽高,相对包含块的位置。大部分情况,DOM树和布局之后的布局树并不是一一对应的。

比如display: none的节点没有几何信息,因此不会生成到布局树中;使用了伪元素选择器,虽然DOM树中不存在这些伪元素节点,但如果他们拥有几何信息,也会被生成到布局树中。

该过程之后会得到一些新的属性,比如:dom.clientWidth

4、分层-Layer

主线程会使用一套复杂的策略对整个布局树进行分层。这样做的目的是,将来某一个层改变后,仅仅对该层进行后续处理,提升效率。

滚动条、堆叠上下文、transform、opacity等样式会影响分层的结果。

5、绘制-Paint

主线程会为每个层单独产生绘制指令集,用于描述这一层的内容应该如何画出来。

6、分块-Tiling

完成绘制后,主线程将每个图层的绘制信息提交给合成线程,剩余工作让合成线程完成。合成线程对每个层进行划分成多个区块。

7、光栅化-Raster

这个阶段是由GPU进程来完成,GPU进程会开启多个线程完成光栅化,并且优先处理靠近视口区域的块。光栅化的结果会得到一块块位图,交回给合成线程。

8、画-Draw

合成线程拿到每个层、块的位图之后,生成一个指引信息。指引信息标识出每个位图应该画在屏幕哪个位置,以及会考虑旋转,缩放等变形。变形发生在合成线程,与渲染主线程无关,这就是transform效率高的本质原因。

合成线程会把指引信息交个GPU进程,由GPU进程产生系统调用,提交给GPU硬件比如显卡,最终完成显示。

你真的了解浏览器的渲染原理吗?

四、什么是回流(reflow)

涉及到页面布局的几何属性的改变会引发回流 ,几何属性的改变需要重新计算布局树,会引发layout,进而导致引发后续所有的过程。

你真的了解浏览器的渲染原理吗?

如果我们使用JS连续多次修改几何属性,因为JS的执行和渲染是互斥,如果在JS修改了某个几何属性之后想立马获取该属性值,可能会造成获取不到最新的值。

为了避免这个问题,浏览器最终决定:

JS获取布局树属性会立即执行reflow,然后返回最新的值

dom.style.width = xx
dom.style.height = xx
dom.margin = xx
dom.clientWidth = xx

五、什么是重绘(repaint)

当修改了可见样式相关的属性,会重新生成绘制指令,进而引发后续过程。

由于元素的布局信息也是属于可见样式,所以reflow一定会引起repaint

转载自:https://juejin.cn/post/7224794158744748088
评论
请登录