Web性能优化
1 Web性能优化
Web网站的性能细线在几个方面:
-
网站首页加载速度
-
动画的流畅度
通过分析浏览器的渲染原理、资源对渲染的影响,得出优化网站性能的办法。
2 查看性能的工具
Chrome的 Timeline
面板录制网页加载的过程,分析记录浏览器渲染过程中每个过程的耗时。
2.1 录制时注意事项
-
禁用浏览器缓存:
Network Tab
下的disable cache
-
关闭Chrome扩展或者启用隐身模式
-
根据使用场景,模拟真实的网络加载情况:
Network Tab
下的throttling
下拉按钮
2.2 Timeline
工具的各个组成
-
在
Main Thread
中可以看到页面渲染的整个过程及耗时
3 浏览器渲染原理
3.1 DOM树构建
DOM树的构建过程
-
根据HTML文档的内容,根据标签进行分词
Token
-
根据
Token
生产对应的节点Node
-
将节点根据嵌套关系组合为一棵对象节点树
DOM
浏览器解析文档对象模型
DOM
是 增量进行的,无需等待整个HTML文档加载完毕,便可以开始解析DOM
CSSOM
解析会阻塞HTML Parser
;JavaScript脚本文件 执行会阻塞HTML解析; CSS、JavaScript、Images和Font等静态资源的异步加载的,渲染页面与CSS解析与JavaScript执行会有相互的依赖
3.2 CSSOM树的构建
CSSOM
的解析依赖于 选择器,选择器的匹配是从内到外的。所以选择器嵌套层次越深,匹配的时间会越长。
CSSOM
只解析可视部分body
标签中的内容,将所有匹配的元素共同构建一个CSSOM
树, 从根节点一次向下,所有节点的属性向下继承
3.3 RenderTree树的构建
利用DOM和CSSOM组合构建生成RenderTree,对应 Recaculate Style
RenderTree中包含所有渲染网页必须的节点
无需渲染的节点不会被添加到RenderTree中,如
head
和display:none;
的节点
visibility: hidden;
的节点会添加到RenderTree中
3.4 Layout
Layout
利用渲染树的信息,计算渲染树中所有节点在页面上的 位置和大小。
类似绘画中各个元素位置摆放及尺寸规划
会引起页面重新Layout的操作: 所有改变节点位置和大小的操作
-
屏幕旋转
-
浏览器视窗改变
-
与大小、位置相关的CSS属性
-
增加与删除DOM元素
Layout操作比较耗时,对于动画中频繁引起Layout的操作(元素位置移动), 最好使用transform代替,可以使用GPU进行动画处理(将Layout重绘在GPU完成)
viewport
如果页面 body
元素设置的宽度为 100%
,并且根元素 html
没有明确设置宽度绝对值, 此时 body
元素的宽度等于 viewport
的宽度 vw
-
使用
meta
标签可以设置浏览器viewport
的尺寸。<meta name="viewport" content="width=device-width">
-
device-width
为浏览器的理想视口(屏幕的物理分辨率) -
在移动端,如果不设置
device-width
,默认viewport
宽度为980px, 导致文字很小,需要放大
viewport
相当于可视内容布局的容器
3.5 Paint
填充Layout中的具体内容和样式,将Layout生成的区域填充为最终显示在屏幕上的像素
3.6 总结
-
浏览器通过
GET
请求获取网页HTML,同时将增量解析HTML文档,生成DOM
树 -
解析
DOM
节点树时,对于需要加载的资源 全部执行异步加载,但是CSS
的解析、JavaScript
的执行与font
文件的下载会阻塞HTML Parser -
局部
DOM
树与CSSOM
树构建完成后, 立即组装RenderTree
进行渲染
4 资源对渲染的影响
页面中加载的资源主要包括: css
、 js
脚本文件和 font
字体与 images
静态资源,不同资源类型对渲染的影响不同。
4.1 浏览器渲染页面的时机
增量解析解析 DOM
树,并且完成相应 CSSOM
解析后(RenderTree依赖于 DOM
树, CSSOM
树),开始直接渲染页面。
4.2 CSS加载会阻塞初次渲染
4.3 非关键资源
对于首页无关的样式,需要使用适当的方式避免其阻塞初次渲染:
-
document.write()
会阻塞页面初次渲染 -
使用
media=print
媒体查询,虽然加载样式表,但只针对打印时才应用该样式,不会阻塞初次渲染。 -
通过
DOM
API引入CSS,可以避免阻塞。 -
CSS中
<link rel="preload" href="index_print.css" as="style" onload="this.rel='stylesheet'">
。
4.4 JS文件
-
输出:先输出
Hello
,10s之后再输出World
。JS脚本 执行会阻塞HTML Parser
,但是HTML Parser
是增量解析的, 并且CSS样式的解析会阻塞JS脚本执行,当解析完Hello
时,生成对应DOM
节点,并且完成其CSSOM
,直接开始渲染Hello
节点。 -
脚本执行完成后再解析后续的
World
JS脚本执行会阻塞HTML Parser;
CSS解析会阻塞JS脚本执行:js可能会读、写CSSOM
虽然JS会阻塞HTML Parser解析; 但是浏览器的资源异步加载机制
Preload
会异步加载head
标签内的资源
4.5 非关键JS资源解析阻塞的优化方案
-
将JS资源文件放在文档底部,延迟JS的执行(但是存在必须解析完HTML才能加载JS资源,相较于
head
标签中加载会慢) -
使用
defer
延迟脚本执行:scipt
标签的defer
属性,脚本会在HTML文档解析完毕后再开始执行; 被defer
的脚本在执行时严格按照HTML文档中出现的顺序执行---优势可以提早加载JS资源,但是解析完HTML再执行 -
使用
async
异步执行脚本:-
当
script
标签有async
属性时,脚本执行不会阻塞HTML Parser,只要脚本加载完毕便开始执行 -
被
async
的脚本,不会严格按照在HTML文档中的顺序执行 -
async
适用于无依赖的外部独立资源(注意不要错误操作状态)
-
4.6 font
字体文件
-
font
字体文件会阻塞内容渲染
4.7 图片资源
图片资源的加载不会阻塞渲染,但是最好在HTML标签中设置图片的高度和宽度,可以在 Layout
时留出图片渲染的空间,避免页面的抖动
5 优化关键渲染路径
优化目标是将下列三个指标压缩到最低:
-
关键资源数---初次渲染时依赖的资源
-
关键资源的体积最小---压缩文件或图片
-
关键资源网络来回数---网络传输资源消耗很多时间
6 其余优化过程
-
HTTP2可以在传输HTML页面后向客户端推送页面内包含的资源
-
减少资源的大小:压缩
-
减少请求的来回时间