前端性能优化及其度量方法
前端页面性能对用户留存、用户直观体验有着重要影响,当页面加载时间超过 2 秒后,加载时间每增加一秒,就会有大量的用户流失,所以做好页面性能优化,对网站来说是一个非常重要的步骤。
提到性能优化,灵魂三问来啦,什么是前端性能优化?如何度量前端性能?如何做性能优化?一个页面的性能指标非常多,面对一大堆性能指标,可能一个老手也一时间不知道从何开始分析,所以本篇文章我会介绍一些性能优化最基础的知识点和工具,以及根据工作分析出数据如何做性能优化,并推荐几个公司个性化需求改造后的性能检测工具。
性能优化及其度量方法
- 优化技术及标准的发展
- 以用户为中心的指标
- 如何做性能优化
- 前端性能分析工具
Terminology优化名词解释
- PWA: Progressive Web Apps, 渐进式Web应用开发,旨在增强 Web 能力,缩小与原生应用的差距并创建与其类似的用户体验
- Lighthouse: 自动化测试工具, 用于测试页面的性能并提出优化建议
- SSR: Server Side Rendering, 在服务端请求数据并组装HTML的渲染方式
- NSR: Native Side Rendering, 在客户端提前请求数据并组装HTML的渲染方式
- Rehydration: [,riːhaɪ’dreɪʃən] 俗称“注水” , 复用服务端渲染生成的 DOM 结构及数据,并执行事件绑定逻辑来启动页面的过程
- RALL模型,Google RAIL 模型提供了一个思考性能问题的方法论
- Navigation Timing :定义的是文档导航过程中完整的性能度量,即文档从发起请求到完成加载的各阶段耗时
- Resource Timing: 记录的是子资源从请求到加载完成各阶段的耗时,了解网络下载资源的阶段至关重要。这是修复加载问题的基础
- TTI (Time to Interactive):页面可交互时间
优化技术及标准的发展
HTTP/1 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷
HTTP/2 通过多路复用、二进制流与 Header 压缩等技术,极大地提高了性能,但是还是存在一些问题
HTTP/3 抛弃 TCP 协议,以全新的视角重新设计 HTTP。其底层支撑是 QUIC 协议,该协议基于 UDP,有 UDP 特有的优势,同时它又取了 TCP 中的精华,实现了即快又可靠的协议
http发展史:
RALL模型:
Google RAIL 模型提供了一个思考性能问题的方法论。
RAIL将用户体验分解为几个关键动作(如点击,滚动,加载),rail模型为这些动作制定了性能目标,RAIL代表的是web应用生命周期内的四个不同的方面。参考:https://web.dev/rail/用户在采取操作后,需要在100ms内收到反馈,用户才不会有延迟感。16ms则对应60fps的每帧处理时间,60fps是动画基本流畅需要达到的帧率。当动画过程出现卡顿或者中断时,用户通常会感觉不爽。
100ms 响应用户输入 每帧动画在16ms内完成 最大化空闲时间 3G 中等设备 5s内可交互
前面提到:
事件处理要求在50ms完成,延时任务执行不能超过50ms
为什么是50ms?
主线程除了处理用户事件,也有其他任务执行,这些任务会占用部分时间,事件处理会排在后面执行。我们的目标是在100ms内对用户事件做出响应,结合图上的任务情况,100ms内需要执行两个任务,分到每个任务就是50ms。
PWA
Web应用在用户体验上往往不如Native应用。首先 Web应用往往依赖网络来加载内容,存在弱网环境加载慢,离线情况无法访问等问题,其次 Web应用也无法添加到桌面,用户需要通过输入url来获取内容。除此之外,Native应用的部分能力在Web也是缺失的,比如消息推送能力。Native应用虽然体验好,但也存在开发成本高、动态性差等问题,用户在使用前需要下载安装。
基于这个背景,谷歌在2016年提出PWA的概念,希望通过增强 Web 能力,缩小与 Native 应用的差距并提供与其类似的用户体验。
PWA有几个重要的特性:
- ServiceWorker: sw可以看成一个可编程网络代理,提供了离线化支持,其中就包括缓存和预加载,sw也是其他PWA特性实现的基础
- APP Manifest: 用来定义 Web 应用的表现和行为,包括桌面图标、闪屏动画、全屏浏览等
- Push & Notification: 为Web应用补齐了消息推送和接收能力
- 离线缓存: 借助sw的离线化能力,用户在离线的情况也能使用部分功能
当然,PWA也包含了其它特性,如读取设备状态、蓝牙分享等,最终的目的都是希望通过渐进增强的方式来逐步达到Native App的体验。
参考:https://whatwebcando.today/ https://web.dev/progressive-web-apps/ https://github.com/GoogleChrome/workbox/
PWA (渐进式Web应用)
目前主流浏览器( Chrome,Safari,Firefox,Edge) 都不同程度上支持了 PWA。国内外一些网站也已进行了 PWA 实践,alibaba.com, 京东等。这些网站在应用 PWA 后也得到了一些可量化的收益。根据谷歌分享的案例,京东印尼站,在使用PWA的缓存、桌面安装、消息推送等能力,转化率提升了53%。https://web.dev/jdid/
Corel Corporation: PWA users are 2.5x more likely to purchase Gravit Designer PRO 12 https://web.dev/gravit-designer/;加拿大的一家公司(科立尔数位科技公司),使用PWA的用户更倾向于购买他们提供的产品。
参考
https://whatwebcando.today/
https://web.dev/progressive-web-apps/
https://github.com/GoogleChrome/workbox/
标准组织
标准的制定离不开标准组织,性能标准也不例外。性能领域有两个重要组织:
一个是1994年成立的W3C,W3C 是 Web 技术领域最具权威和影响力的国际中立性标准机构
另一个是W3C在2010年成立的Web性能工作组,Web 性能工作组的目标就是制定 衡量Web应用性能的方法和 API
- 1994年 W3C (World Wide Web Consortium) 成立
- 2010年 W3C 成立了 Web 性能工作组
标准的发展
这些API可以大致分为3大类,
- 第一类是框架类API:主要包含最左边部分,High Resolution time, performace timingline,提供的高精度时间接口,以及查询性能数据的接口
- 第二类是度量类API: 用来检测页面生命周期内不同方面的性能数据, 对应中间的各种 Timing API 以及 Long Tasks API
- 第三类是优化策略API: 用来改善页面性能,主要分布最右边,提供 页面可见性,任务调度,预加载等能力
参考:
https://www.w3.org/PM/Groups/repositories.html?gid=45211
Element Timing: https://github.com/WICG/element-timing
https://github.com/WICG/layout-instability
Performance Timeline
Performance Timeline 包含几个部分
navigation-timing
:navigation of the document 高精度时间resource-timing
:页面资源 获取各类性能数据的查询接口user-timing
:开发者自定义的一些监控, 主要是(mark 和 measure,下文会讲)两个基础类
- 其中PerformanceEntry是其他Timing Entry的基类,通过getEntries 返回的Entry列表,都继承自PerformanceEntry,每个performaceEnrty
- PerformanceObserver 用于基于事件的指标测量
浏览器支持的entryTypes类型可以通过PerformanceObserver.supportedEntryTypes 提供的接口来查询
High Resolution Time
- performance.now()
- performance.timeOrigin
- performance.toJSON()
三个接口
- getEntries()
- getEntriesByType()
- getEntriesByName()
两个对象
- PerformanceEntry
- PerformanceObserver
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({
type: 'largest-contentful-paint', buffered: true});
Navigation Timing
Navigation Timing 定义的是文档导航过程中完整的性能度量,即文档从发起请求到完成加载的各阶段耗时
- navigationStart 加载起始时间
- redirectStart 重定向开始时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回开始重定向的fetchStart的值。其他情况,则返回0)
- redirectEnd 重定向结束时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回最后一次重定向接受完数据的时间。其他情况则返回0)
- fetchStart 浏览器发起资源请求时,如果有缓存,则返回读取缓存的开始时间
- domainLookupStart 查询DNS的开始时间。如果请求没有发起DNS请求,如keep-alive,缓存等,则返回fetchStart
- domainLookupEnd 查询DNS的结束时间。如果没有发起DNS请求,同上
- connectStart 开始建立TCP请求的时间。如果请求是keep-alive,缓存等,则返回domainLookupEnd
- (secureConnectionStart) 如果在进行TLS或SSL,则返回握手时间
- connectEnd 完成TCP链接的时间。如果是keep-alive,缓存等,同connectStart
- requestStart 发起请求的时间
- responseStart 服务器开始响应的时间
domLoading
:这是整个过程的起始时间戳,浏览器即将开始解析第一批收到的 HTML 文档字节。domInteractive
:表示浏览器完成对所有 HTML 的解析并且 DOM 构建完成的时间点。domContentLoaded
:表示 DOM 准备就绪并且没有样式表阻止 JavaScript 执行的时间点,这意味着现在我们可以构建渲染树了。- 许多 JavaScript 框架都会等待此事件发生后,才开始执行它们自己的逻辑。因此,浏览器会捕获
EventStart
和EventEnd
时间戳,让我们能够追踪执行所花费的时间。
- 许多 JavaScript 框架都会等待此事件发生后,才开始执行它们自己的逻辑。因此,浏览器会捕获
domComplete
:顾名思义,所有处理完成,并且网页上的所有资源(图像等)都已下载完毕,也就是说,加载转环已停止旋转。loadEvent
:作为每个网页加载的最后一步,浏览器会触发onload
事件,以便触发额外的应用逻辑。- unloadEventStart unload事件触发的时间
- unloadEventEnd unload事件执行完的时间
- performance.timing:页面导航性能可以通过 performance.timing 获得
- performance.navigation.type:NavigationType表示导航的类型,目前有四种类型,分别表示导航