性能优化的目的
提升用户体验 和 节约资源成本。包括:
- 优化页面加载速度
- 减少服务器压力
- 减少网络带宽的开销
性能优化三部曲
- 收集性能数据
- 分析数据,找出性能瓶颈
- 指定优化方案,持续优化
性能优化核心指标
性能指标 | 说明 |
---|---|
白屏时间 | 从浏览器响应用户输入网址开始,到显示页面第一个元素的时间(开始渲染<body>标签或刚解析完<head>)。 |
首屏时间 | 指浏览器从响应用户输入网址,到首屏内容渲染完成的时间。 |
用户可操作时间 | document.readyState变为domInteractive的时间节点,此时已经完成DOM结构解析,只是图片、样式等还没加载出来。 |
总下载时间 | load事件触发的时间节点。此时页面已经加载完毕(包括样式、图片都已经加载好了)。 |
白屏时间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>白屏</title>
<script type="text/javascript">
let pf = performance || webkitPerformance || msPerformance || mozPerformance || {};
pf.now =
pf.now ||
pf.webkitNow ||
pf.msNow ||
pf.mozNow;
window.pageStartTime_navigationStart = pf.timing&&pf.timing.navigationStart;
window.pageStartTime_timingnow = pf.now();
window.performance = pf;
</script>
<!-- 页面 CSS 资源 -->
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
<script type="text/javascript">
if(window.pageStartTime_navigationStart){
window.firstPaint = Date.now();
window.whiteScreenTime = window.firstPaint - window.pageStartTime_navigationStart;
}else {
window.firstPaint = window.performance.now();
window.whiteScreenTime = window.firstPaint - window.pageStartTime_timingnow;
}
</script>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>
参考概念
页面生命周期
事件 | 说明 |
---|---|
DOMContentLoaded | DOM树已经构建完毕,但IMG和CSS等外部资源未必加载完毕。 |
load | 所有资源加载完毕,包括IMG和CSS等外部资源。 |
unload | 即将离开页面。 |
页面加载状态
通过document.readyState可获取当前页面加载状态。
状态 | 说明 |
---|---|
loading | document仍在加载 |
interactive | 文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载 |
complete | 文档和所有子资源已完成加载。状态表示 load 事件即将被触发 |
采集指标数据方法
Performance
这是一个用于前端性能监控的WEB API。
performance.timing
在浏览器访问一个页面,从输入URL到最终看到页面的过程中,可以通过performance.timing获取到中间过程节点的时间信息。
基于performance.timing我们可以采集计算得到以下指标数据:
性能优化方法
- 离线化
- 请求前置
- 数据缓存
雅虎军规
-
尽量减少 HTTP 请求个数(须权衡)
-
使用 gzip 压缩内容
-
保持单个内容小于25K
-
精简 CSS 和 JS
-
剔除重复的 JS 和 CSS
-
优化 CSS Spirite
-
favicon.ico要小而且可缓存
-
使用 CDN(内容分发网络)
-
为文件头指定 Expires 或 Cache-Control ,使内容具有缓存性。
-
使 AJAX 可缓存
-
配置 ETags
-
避免空的 src 和 href
-
把 CSS 放到顶部
-
把 JS 放到底部
-
延迟加载
-
预加载
-
避免使用 CSS 表达式
-
将 CSS 和 JS 放到外部文件中
-
减少 DNS 查找次数
-
减少 Cookie 的大小
-
避免跳转
-
尽早刷新输出缓冲
-
使用 GET 来完成 AJAX 请求
-
减少 DOM 元素个数
-
根据域名划分页面内容
-
尽量减少 iframe 的个数
-
避免 404
-
使用无 cookie 的域
-
减少 DOM 访问
-
开发智能事件处理程序
-
用 代替 @import
-
避免使用滤镜
-
优化图像
-
不要在 HTML 中缩放图像——须权衡
-
打包组件成复合文本
首屏秒打开
网络请求
网络请求是影响首页打开速度的一个大因素,常见优化方法有:
-
减少网络请求次数
-
减小文件体积
-
使用
CDN
加速
对JS、CSS、图片进行合并压缩,并使用CDN分发
- 合并压缩后,单个文件控制在 25 ~ 30 KB左右,同一个域下,最好不要多于5个资源。
- 图片的合并可以采用
CSSSpirite
,方法就是把一些小图用PS
合成一张图,用css
定位显示每张图片的位置。- 大的图片在不同终端,应该使用不同分辨率,而不应该使用缩放(百分比)
defer和async优化
浏览器是按顺序来解析HTML的,当遇到
<script>
标签时,将会立刻加载并执行<script>脚本,在这期间会阻塞DOM树的构建(UI渲染线程与JS引擎线程是互斥的),从而延长了白屏时间。<script>标签提供了两个属性来解决上述问题,async和defer。这两个属性只对外部脚本有效。
defer表示脚本将会异步下载,并且在DOM树构建完毕后,
DOMContentLoaded
事件调用前按HTML中的顺序执行。所以defer脚本的下载和执行都不会阻塞DOM树的构建。async表示脚本将会异步下载,但与defer不同的是,async脚本下载后会立刻执行,并不会按照到HTML中的顺序执行。所以async脚本的执行可能会阻塞DOM树构建。