浏览器渲染

渲染原理

内核

内核,浏览器运行的核心。内核主要有两个部分:渲染引擎、js引擎。渲染引擎在不同浏览器、不同内核中,渲染引擎都不一样。

常见的内核

  • Trident(IE)

  • Gecko(火狐)

  • Blink(Chrome、Opera)

  • Webkit(Safari)

页面加载过程

  • 通过DNS获取域名对应的IP地址

  • 向IP发送HTTP请求

  • 服务器处理返回HTTP请求

  • 浏览器解析服务器返回的内容

渲染过程

image

渲染过程大致分为一下三部分:

  1. HTML、CSS、JS解析
  • 对于HTML/SVG/XHTML,浏览器会把对应内容转换成DOM树形结构

  • 解析生成CSS规则树

  • 解析执行JS脚本,在脚本加载完成后,执行脚本

  1. 在解析完成后,合并DOM树与CSS规则树,生成渲染树(Rendering Tree)
  • 渲染树与DOM树不同,渲染树只会包括需要显示的节点和相对节点的样式信息

  • CSS规则树主要作用是为渲染树上的节点加上相对应的CSS规则

  • 计算每个元素的位置,该过程称为重绘(repaint)和回流(reflow)

  1. 调用系统的绘图API进行图形绘制

构建DOM

浏览器将读取到的HTML文件转换为DOM树

构建CSSOM(CSS规则树)

DOM树主要说明页面内容有什么,但怎么展示内容,还需要CSSOM

CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去。

构建渲染树

在得到DOM树与CSSOM树后,需要将两者合并为渲染树进行显示

  • 渲染树中只会包含需要显示的节点及其样式信息

  • 如果遇到<script> 标签,就会停止渲染,执行JS代码(可以通过asyncdefer 修改<script> 行为

<script> 不仅会阻塞DOM的构建,还会导致CSS规则树构建也阻塞

原本DOM和CSSOM的构建是互不影响,井水不犯河水,但是一旦引入了JavaScript,CSSOM也开始阻塞DOM的构建,只有CSSOM构建完毕后,DOM再恢复DOM构建。

这是因为JavaScript不只是可以改DOM,它还可以更改样式,也就是它可以更改CSSOM。因为不完整的CSSOM是无法使用的,如果JavaScript想访问CSSOM并更改它,那么在执行JavaScript时,必须要能拿到完整的CSSOM。所以就导致了一个现象,如果浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。

asyncdefer 的作用

  • async 异步下载

  • defer 延迟执行

  • 载入 JavaScript 文件时不阻塞 HTML 的解析,执行阶段被放到 HTML 标签解析完成之后。 在加载多个JS脚本的时候,async是无顺序的加载,而defer是有顺序的加载。

重绘、回流

  • 浏览器的默认布局模型为流式布局模型

  • 浏览器把HTML 解析成DOM ,把CSS 解析成CSSOM ,然后把两者合并生成Render Tree

  • 通过渲染树进行计算每个需要显示的节点的大小与位置,最后进行绘制显示

  • 如果使用流式布局,则对Render Tree 的计算通常只需要遍历一次

回流必将重绘,重绘不一定回流

回流(Reflow)

Render Tree 中部分或全部元素的大小,结构或某些属性发生改变时,浏览器及将重新渲染部分或全部元素,此过程称为回流

当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)

会导致回流的操作

  • 首次渲染

  • 浏览器窗口大小改变

  • 元素的大小、位置改变

  • 元素内容、字体大小变化

  • 添加或删除可见的元素

  • 激活CSS 伪类

  • 查询某些属性或调用某些方法

会导致回流的属性、方法

  • clientWidthclientHeightclientTopclientLeft

  • offsetWidthoffsetHeightoffsetTopoffsetLeft

  • scrollWidthscrollHeightscrollTopscrollLeft

  • scrollIntoView()scrollIntoViewIfNeeded()

  • getComputedStyle()

  • getBoundingClientRect()

  • scrollTo()

重绘(Repaint)

当页面中的元素样式的改变并不影响它的大小和位置时,浏览器将重新绘制元素,此过程称为重绘

当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式

常见的会引起重绘的属性和方法

重绘与回流的机制

有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流

浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。

当访问以下属性或方法时,浏览器会立即清空队列:

  • clientWidthclientHeightclientTopclientLeft

  • offsetWidthoffsetHeightoffsetTopoffsetLeft

  • scrollWidthscrollHeightscrollTopscrollLeft

  • widthheight

  • getComputedStyle()

  • getBoundingClientRect()

在队列中的重绘、回流可能会影响到以上属性或方法的返回值,因此浏览器需要清空队列,确保返回值的准确

浏览器的调试技巧

设置断点

开发者工具

条件断点

代码中下断点

// 以下代码可以防止调试网站源码
// 在打开开发者工具后,每秒钟触发一次断点,防止调试源码
(function() {
	setInterval(function() {
		debugger
	}, 1000)
})()

禁用断点

参考资料

浏览器渲染open in new window