# 浏览器工作原理系列之4-如何进行性能优化?
# 前言
本文分为一下几个部分:
- 性能优化概述
- 性能检测和性能指标
- 页面呈现过程
- 性能优化策略
# 一、性能优化概述
网站性能优化分为:
- 存储服务器性能优化
- 应用服务器性能优化
- Web性能优化
Web性能如何定义:
- 客观性能:从开发者视角出发,可度量的客观性能
- 主观性能:从用户视角触发,可感知的主观性能
那么好的网站性能有什么好处呢?
- 用户体验
- 业务价值
性能优化越来越受到重视:
- 蛮荒时代:自由摸索
- 社区时代:由部分厂商推出最佳实践,如2007年雅虎35条军规、2014年谷歌推出Web开发最佳实践手册、2017年谷歌推出PWA和Lighthouse检测工具
- 标准时代:1994年W3C成立,2010年W3C成立Web性能工作组
# 二、性能检测和性能指标
# 性能检测
API
Performance标准:对性能进行度量。
- 高精度时间
- now() 距离当前时间ms
- timeOrigin 页面初始时间戳
- toJSON()
- 性能时间线
- getEntries()
- getEntriesByType()
- getEntriesByName()
资源请求时序
导航过程相关
- navigation对象
- timing对象
- 绘制关键时间点
- First Paint(FP)
- First Contentful Paint(FCP)
- 用户自定义时间节点
- mark()
- clearMarks()
- measure()
- clearMeasures()
获取服务端各节点性能
检测长任务
工具
- 鲁班尺:UC鲁班尺是基于Lighthouse来做的,它会分析页面在内核中真实渲染的情况, 并给出优化建议。
- 海鸥实验室:UC海鸥实验室是一个性能分析平台,它可以提供完善的首屏、内存、启动、帧率分析数据。
- 岳鹰全景监控平台:是阿里UC官方出品的先进移动应用线上监控平台
- 腾讯云性能监控平台 (opens new window):(Real User Monitoring,RUM)一站式前端监控解决方案
- Lighthouse:检测页面性能瓶颈。
- Timeline:记录页面运行过程的具体细节,用于分析页面出现问题的具体位置。
- Profile:分析页面内存的使用情况和JS/CSS执行时间。一般可以用TImeline定位出大概位置,再用JavaScript CPU profiler详细分析每个JS函数的耗时。
- Chrome Trace:记录页面在浏览器内核执行的完整过程,粒度精细到每个函数方法,可以很准确的定位到具体问题。
# 性能指标
随着人们对性能优化的认识不断更新和变化,挑选了页面呈现过程中的许多时间节点,作为性能的参考指标。而你只需关注你看重的性能指标即可。
# 指标一览
文档加载
- TTFB(Time To First Byte):浏览器从请求页面开始到接收第一字节的时间,这个时间段内包括 DNS 查找、TCP 连接和 SSL 连接。
- DCL(DomContentLoaded):当HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架加载完成
- Load:页面所有资源都加载完毕后(比如图片,CSS),onLoad 事件才被触发。
内容呈现
- FP(First Paint): 从开始加载到浏览器首次绘制像素到屏幕上的时间。这是开发人员关心页面加载的第一个关键时刻——当浏览器开始呈现页面时。
- First Contentful Paint(FCP):浏览器首次绘制来自 DOM 的内容的时间,内容必须是文本、图片(包含背景图)、非白色的 canvas 或 SVG,也包括带有正在加载中的 Web 字体的文本。这是用户第一次开始看到页面内容,但仅仅有内容,并不意味着它是有用的内容(例如 Header、导航栏等),也不意味着有用户要消费的内容。另外,字体加载是影响 FCP 的一个重要因素,字体通常是需要一段时间才能加载的大文件,有些浏览器在加载字体之前会隐藏文本。为了确保在 webfont 加载期间文本保持可见,可以临时显示系统字体
- First Meaningful Paint(FMP)(不推荐):页面的主要内容绘制到屏幕上的时间,这是一个更好的衡量用户感知加载体验的指标,但仍然不理想。主要内容的定义因页面而异,例如对于博客文章,它的主要内容是标题和摘要,对于搜索页面,它的主要内容是搜索结果,对于电商的页面,图片则是主要内容。所以采用 布局数量最大并且 Web 字体已加载 的时刻作为主要内容绘制的近似时间。
- Largest Contentful Paint(LCP):可视区域中最大的内容元素呈现到屏幕上的时间,用以估算页面的主要内容对用户可见时间。
- Speed Index(SI):这是一个表示页面可视区域中内容的填充速度的指标,可以通过计算页面可见区域内容显示的平均时间来衡量。
- First Screen Paint(FSP):页面从开始加载到首屏内容全部绘制完成的时间,用户可以看到首屏的全部内容。如果说 LCP 是用户看到有效内容的最近似的时间,那么在 FSP 这个时间点用户已经看到了可视区域内完整的内容,可以说是衡量用户视觉体验最合适的指标。
交互响应
- Time To Interactive(TTI):表示网页第一次完全达到可交互状态的时间点,浏览器已经可以持续性的响应用户的输入。完全达到可交互状态的时间点是在最后一个长任务(Long Task)完成的时间, 并且在随后的 5 秒内网络和主线程是空闲的。从定义上来看,中文名称叫可持续交互时间或可流畅交互时间更合适。长任务是需要 50 毫秒以上才能完成的任务
- First CPU Idle(FCI)(不推荐):页面第一次可以响应用户输入的时间。FCI 和 TTI 都是页面可以响应用户输入的时间。FCI 发生在用户可以开始与页面交互时;TTI 发生在 用户完全能够(可持续) 与页面交互时。第一次可交互与可流畅交互的时间点如何确定可以在 Google 的 First Interactive and Consistently Interactive中查阅。
- First Input Delay(FID):从用户第一次与页面交互(例如单击链接、点击按钮等)到浏览器实际能够响应该交互的时间。输入延迟是因为浏览器的主线程正忙于做其他事情,所以不能响应用户。发生这种情况的一个常见原因是浏览器正忙于解析和执行应用程序加载的大型 JavaScript 文件。第一次输入延迟通常发生在第一次内容绘制(FCP)和可持续交互时间(TTI)之间,因为页面已经呈现了一些内容,但还不能可靠地交互。
- Frames Per Second(FPS):帧率是视频设备产生图像(或帧)的速率,用每秒可以重新绘制的帧数(Frames Per Second,FPS)表示。重新绘制可能需要重新计算样式、布局和绘制,如果每帧绘制到屏幕的时间在 16.7 ms 以上,每秒绘制的帧数就会小于 60 帧,人眼就能感受到页面出现卡顿,所以 FPS 是衡量应用流畅度的一个非常重要的指标,60fps 是页面流畅的目标,可以为每次绘制提供 16.7ms 的时间预算
# 用户体验核心指标
- 白屏时间:页面开始有内容的时间,FP或FCP
- 首屏时间:可视区域内容已完全呈现的时间,LCP或FSP
- 可交互时间:用户第一次可以与页面交互的时间 FCI
- 可流畅交互时间:用户第一次可以持续与页面交互的时间,TTI
# Lighthouse Metrics
- FCP(First Contentful Paint)
- TTI(Time to interactive)
- SI(Speed Index)
- TBT(Total Blocking Time)
- LCP(Largest Contentful Paint)
- CLS(Cumulative Layout Shift)
有了指标后,我们就有了衡量页面性能的具体依据。
接着,我们开始着手对我们关心的指标进行优化了。
然而,指标只是页面呈现过程的一种时间度量,比如LCP2.6s,说明页面载入2.6s后,可视区域中的最大元素被渲染出来。优化的目标则是将2.6s缩短,比如缩短到1.6s。
因此,为了缩短这个时间,我们还需要了解页面载入到可视区域的最大元素被渲染这个过程中,发生了哪些事情。
# 三、页面呈现过程
- 加载过程
- DNS解析URL
- 内部重定向
- 查找HTTP缓存
- 发起网络请求
- 应用层:DNS解析、准备HTTP请求消息
- 表示层:HTTP/2二进制分帧
- 会话层:应用程序委托操作系统建立TCP连接、TLS协商
- 传输层:封装成报文段
- 网络层:封装成数据报
- 数据链路层:封装成帧
- 物理层:数字转换为电信号
- 请求达到代理服务器
- CDN服务器
- 负载均衡器
- 请求转发到服务器
- 拆包和组装
- 处理请求
- 返回响应
- 浏览器接收响应
- HTTP重定向
- 检测响应体
- 渲染过程
- 解析HTML
- 预解析
- 下载CSS、JS(主要瓶颈)
- 执行JS(主要瓶颈)
- 生成CSSOM、DOM
- 生成布局树(Layout Tree)
- 生成图层树(分层)(Layer Tree)
- 生成绘制列表(Paint List)
- 光栅化(光栅化线程池):按照绘制列表中的指令生成图片
- 分块(合成线程)
- 合成(合成线程)
- 解析HTML
# 四、性能优化策略
通过上一部分,我们了解了页面呈现的整个过程,这一部分,我们将针对其中的众多环节,提出一些优化方案。
- 加载阶段:优化关键资源的加载速度(关键资源:能阻塞网页首次渲染的资源)
- 减少关键资源的数量
- 内联JS/CSS
- 异步加载JS
- 异步加载CSS
- 合理利用缓存
- 减少关键资源的大小
- 代码压缩
- Tree-Shaking(清除多余代码优化打包体积)
- 降低关键资源的RTT(Round Trip Time)
- 合理使用缓存
- CDN加速
- HTTP2多路复用
- DNS prefetch 域名提前寻址
- 减少关键资源的数量
- 渲染/交互阶段:让单个帧的生成速度变快
- 图片优化
- 图片预加载
- 预加载LCP大图
- 图片格式/尺寸优化
- 异步加载屏幕外的图片
- iconfont,css代替图片
- 减少JS脚本执行时间(使用Web Worker)
- 合理使用CSS动画(利用合成>重绘>重排)
- 使用RAF代替SetTImeout实现JS动画(RAF更准)
- 图片优化
# 总结
本章主要目的是构建一个网页性能优化的理论知识体系,主要介绍了:
- 性能优化的演进历史
- 性能检测和性能指标
- 页面呈现过程
- 性能优化策略