面试时被问到一个老生常谈的问题浏览器输入URL并敲下回车后会发生什么的时候,前后过程先不考虑,就从 HTTP 链接建立并获取到入口 Html 文件开始,到页面渲染出第一个字节的时候,都发生了什么事情呢?
已知,浏览器已经拿到了我们的 html 文件,那就得从上到下的读取,边读就得边干点儿什么事儿,这个一边读一边干的过程、或者说步骤,叫做关键渲染路径(CRP:Critical Rendering Path)。接下来一起聊聊这个玩意。
关键渲染路径
关键渲染路径是浏览器将 HTML、CSS 和 JavaScript 转换为屏幕上的像素所经历的步骤序列,也就是一边读html文档一边要干的事儿。所以如果能对其进行一些优化,也就能提高一些渲染的性能。
DOM树
首先,浏览器在读取 HTML 文档的过程中,会去构建文档对象模型,也叫 DOM 树,这颗树是以对象的形式存在在内存中的,并且允许 JavaScript 去读取和改写。
在从上到下构建 DOM 的过程中,会被外部资源阻塞(css 文件、js 文件、Image 文件等)等到处理完这些文件的请求后,才会继续向下进行,直到 HTML 文件的末尾。
DOM树的构建是增量的(就是一点一点往上添加),节点越多,这个构建的过程越长,所以理论上来说,我们并不应该在编写 HTML 代码的时候增加过多无意义的 Node 节点,不过这些无意义的节点达到什么量级才会从体验上影响用户呢,我也没有测试过,欢迎大家测试一下(不过几个冗余的节点应该没有多大影响)。
CSSOM树
浏览器读到HTML文档末尾时,此时 DOM 树也构建完成,就开始构建CSS 对象模型,也叫 CSSOM 树,浏览器会收集所有的 style 标签内容、css 文件来进行 CSSOM 的构建,需要注意的是CSSOM和 DOM 很像,但又有一些不一样的地方:
- DOM 是增量的,CSSOM 不是
- CSS 是阻塞渲染的
- 浏览器会阻塞页面渲染,直到它接收和执行了所有的 css。
终其原因是因为 CSS 会被覆盖,它没办法像 DOM 一点点往上加就行,必须要拿到所有的 css 去做优先级的衡量、对比,最后完成 CSSOM 的构建。
CSS 的选择器会对 CSSOM 构建起到影响作用,我们都知道,选择器越复杂,则一般情况下优先级越高,但是同时,浏览器的工作量越大(得一个选择器一个选择器的找),所以我们心里肯定想,哦,以后要简化一些,要提高性能。其实也大可不必,因为浏览器其实在这方面非常擅长,活儿干的多,速度可一点不慢,花心思在这里优化,其实提升的速度并不明显。
可以通过下面的方式来优化 CSS
- 分片加载(不同屏幕加载不同的 CSS 文件)
- 移除用不到的 CSS 代码(css-trickes)
- 压缩 css 文件...
渲染树
DOM 和 CSSOM 构建完成后,浏览器开始构建渲染树,计算所有可见内容的样式。一旦渲染树完成,布局就会开始,定义所有渲染树元素的位置和大小。在布局完成后,页面将被渲染或“绘制”到屏幕上。
渲染树上不会有看不见的东西,比如 Head 中的内容、设置 css 为 display:none 的内容及其后代。
渲染树创建完成后,就会第一次的将页面内容绘制到浏览器窗口中,此时用户就可以看到页面内容啦(这个时间节点就是FP / FCP)
后续再通过 JS 对页面进行内容和样式的修改的时候,会先更新对应的渲染树的内容,然后将这部分更新后的渲染树绘制到页面上。
CRP优化
提升页面加载速度需要通过被加载资源的优先级、控制它们加载的顺序和减小这些资源的体积。性能提示包含
- 通过异步、延迟加载或者消除非关键资源来减少关键资源的请求数量
- 优化必须的请求数量和每个请求的文件体积
- 通过区分关键资源的优先级来优化被加载关键资源的顺序,来缩短关键路径长度。
总结
下面两个图基本可以看清楚啦: