前端性能优化及其度量方法

2,445 阅读23分钟

前端性能优化及其度量方法

前端页面性能对用户留存、用户直观体验有着重要影响,当页面加载时间超过 2 秒后,加载时间每增加一秒,就会有大量的用户流失,所以做好页面性能优化,对网站来说是一个非常重要的步骤。

提到性能优化,灵魂三问来啦,什么是前端性能优化?如何度量前端性能?如何做性能优化?一个页面的性能指标非常多,面对一大堆性能指标,可能一个老手也一时间不知道从何开始分析,所以本篇文章我会介绍一些性能优化最基础的知识点和工具,以及根据工作分析出数据如何做性能优化,并推荐几个公司个性化需求改造后的性能检测工具。

性能优化及其度量方法

  1. 优化技术及标准的发展
  2. 以用户为中心的指标
  3. 如何做性能优化
  4. 前端性能分析工具

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发展史:

image-20210209153449941

RALL模型

Google RAIL 模型提供了一个思考性能问题的方法论。

RAIL将用户体验分解为几个关键动作(如点击,滚动,加载),rail模型为这些动作制定了性能目标,RAIL代表的是web应用生命周期内的四个不同的方面。参考:web.dev/rail/用户在采取操…

image-20210209154134977

100ms 响应用户输入 每帧动画在16ms内完成 最大化空闲时间 3G 中等设备 5s内可交互

前面提到:

事件处理要求在50ms完成,延时任务执行不能超过50ms

为什么是50ms?

主线程除了处理用户事件,也有其他任务执行,这些任务会占用部分时间,事件处理会排在后面执行。我们的目标是在100ms内对用户事件做出响应,结合图上的任务情况,100ms内需要执行两个任务,分到每个任务就是50ms。

image-20210209154601971

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的离线化能力,用户在离线的情况也能使用部分功能

image-20210209154621040

当然,PWA也包含了其它特性,如读取设备状态、蓝牙分享等,最终的目的都是希望通过渐进增强的方式来逐步达到Native App的体验。

参考:whatwebcando.today/ web.dev/progressive… github.com/GoogleChrom…

PWA (渐进式Web应用)

目前主流浏览器( Chrome,Safari,Firefox,Edge) 都不同程度上支持了 PWA。国内外一些网站也已进行了 PWA 实践,alibaba.com, 京东等。这些网站在应用 PWA 后也得到了一些可量化的收益。根据谷歌分享的案例,京东印尼站,在使用PWA的缓存、桌面安装、消息推送等能力,转化率提升了53%。web.dev/jdid/

Corel Corporation: PWA users are 2.5x more likely to purchase Gravit Designer PRO 12 web.dev/gravit-desi…

参考

whatwebcando.today/

web.dev/progressive…

github.com/GoogleChrom…

标准组织

标准的制定离不开标准组织,性能标准也不例外。性能领域有两个重要组织:

一个是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: 用来改善页面性能,主要分布最右边,提供 页面可见性,任务调度,预加载等能力

image-20210209155414059

参考:

www.w3.org/PM/Groups/r…

Element Timing: github.com/WICG/elemen…

github.com/WICG/layout…

Performance Timeline

Performance Timeline 包含几个部分

  1. navigation-timing:navigation of the document 高精度时间
  2. resource-timing:页面资源 获取各类性能数据的查询接口
  3. 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

image-20210218150601786

image-20210218150723078

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 定义的是文档导航过程中完整的性能度量,即文档从发起请求到完成加载的各阶段耗时

image-20210209160255513

image-20210218195501488

  1. navigationStart 加载起始时间
  2. redirectStart 重定向开始时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回开始重定向的fetchStart的值。其他情况,则返回0)
  3. redirectEnd 重定向结束时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回最后一次重定向接受完数据的时间。其他情况则返回0)
  4. fetchStart 浏览器发起资源请求时,如果有缓存,则返回读取缓存的开始时间
  5. domainLookupStart 查询DNS的开始时间。如果请求没有发起DNS请求,如keep-alive,缓存等,则返回fetchStart
  6. domainLookupEnd 查询DNS的结束时间。如果没有发起DNS请求,同上
  7. connectStart 开始建立TCP请求的时间。如果请求是keep-alive,缓存等,则返回domainLookupEnd
  8. (secureConnectionStart) 如果在进行TLS或SSL,则返回握手时间
  9. connectEnd 完成TCP链接的时间。如果是keep-alive,缓存等,同connectStart
  10. requestStart 发起请求的时间
  11. responseStart 服务器开始响应的时间
  12. domLoading:这是整个过程的起始时间戳,浏览器即将开始解析第一批收到的 HTML 文档字节。
  13. domInteractive:表示浏览器完成对所有 HTML 的解析并且 DOM 构建完成的时间点。
  14. domContentLoaded:表示 DOM 准备就绪并且没有样式表阻止 JavaScript 执行的时间点,这意味着现在我们可以构建渲染树了。
    • 许多 JavaScript 框架都会等待此事件发生后,才开始执行它们自己的逻辑。因此,浏览器会捕获 EventStartEventEnd 时间戳,让我们能够追踪执行所花费的时间。
  15. domComplete:顾名思义,所有处理完成,并且网页上的所有资源(图像等)都已下载完毕,也就是说,加载转环已停止旋转。
  16. loadEvent:作为每个网页加载的最后一步,浏览器会触发 onload 事件,以便触发额外的应用逻辑。
  17. unloadEventStart unload事件触发的时间
  18. unloadEventEnd unload事件执行完的时间
  • performance.timing:页面导航性能可以通过 performance.timing 获得
  • performance.navigation.type:NavigationType表示导航的类型,目前有四种类型,分别表示导航、刷新、前进后退、预渲染
  • performance.navigation.redirectCount:从时间轴可以看到,navigation timing复用了 Resource Timing的时间轴,即图中橙色部分
enum NavigationType {

  "navigate",

  "reload",

  "back_forward",

  "prerender"

};
Resource Timing

Resource Timing 记录的是子资源从请求到加载完成各阶段的耗时,了解网络下载资源的阶段至关重要。这是修复加载问题的基础。

  • 了解资源时序的阶段。
  • 知道每个阶段提供给Resource Timing(资源时序)API。
  • 在时间轴图表中识别性能问题的不同指示。如连续的透明条或大块绿色。

image-20210209160440771

所有网络请求都被视为资源。当它们通过网络检索时,分为不同的生命周期。Network(网络)面板使用的Resource Timing API和提供给开发者的API是一样的。

注意: 当使用跨源资源的Resource Timing API时, 请确保所有资源都有CORS头信息。

Resource Timing API提供了关于每个单独资源接收时间的详细信息。 请求生命周期的主要阶段是:

  • Redirect
    

    (重定向)

    • 立即开始startTime
    • 如果发生重定向, redirectStart也会开始计时。
    • 如果重定向发生在此阶段结束时,那么redirectEnd将被采用。
  • App Cache
    

    (应用程序缓存)

    • 如果浏览器有缓存,将采用fetchStart时间。
  • DNS
    
    • domainLookupStart 记录DNS请求开始的时间。
    • domainLookupEnd 记录DNS请求结束的时间。
  • TCP
    
    • connectStart 记录开始连接到服务器的时间。
    • 如果用了TLS或SSL,secureConnectionStart记录开始连接时间。
    • connectEnd 记录连接完毕时间。
  • Request
    

    (请求)

    • requestStart记录请求发送到服务器的时间。
  • Response
    

    (响应)

    • responseStart记录最开始的响应时间。
    • responseEnd记录响应结束时间。

子资源的性能数据可以通过指定 entryType 为 resource 来查询,

performance.getEntriesByType('resource') 

需要注意的是:对于跨域资源的性能数据,需要正确返回 timing-allow-origin: * 才能被页面采集到

Paint Timing
  • 收集 FP, FCP 两个指标

  • name: first-paint 首次绘制

  • name: first-contentful-paint 首次内容绘制

    image-20210209160758620

var observer = new PerformanceObserver(function(list) {

  var perfEntries = list.getEntries();

  for (var i = 0; i < perfEntries.length; i++) {

​    Console.log(perfEntries.length[i]);

  }

});

observer.observe({entryTypes: ["paint"]});
Event Timing
  • WICG 的一个提案
  • 跟踪用户输入的处理延迟

Event Timing 提出的背景是需要跟踪输入事件的处理延迟,目前处于草案阶段;可以用来计算 首次输入延迟(FID) 这个指标,算法也比较简单,开始处理时间-接收时间得到;参考:wicg.github.io/event-timin…

Frame Timing

Frame Timing,用来记录一些慢帧信息,目前处于提案阶段:wicg.github.io/frame-timin…

image-20210209161244828

  • 其中一帧定义为两个vsync之间的时间间
  • 在60HZ刷新率的屏幕下,每帧的时间上限是16ms
new PerformanceObserver((list) => {

const perfEntries = list.getEntries();

for (let i = 0; i < perfEntries.length; i++) {

 // Process slow-frame notifications

 console.log("Uh oh, slow frame: ", perfEntries[i]);

}

});

observer.observe({entryTypes: ['frame']});
Long Tasks API

Long Tasks API,用来监控主线程的长任务 : Long task > 50ms

  • 长任务会阻塞主线程,导致无法快速响应用户输入。对于长任务,一般的手段是通过合理拆分成子任务来优化
  • 通过 PerformanceObserver 来采集
var observer = new PerformanceObserver((list) => {

  var perfEntries = list.getEntries();

  for (var i = 0; i < perfEntries.length; i++) {

​    // Process long task notifications:// report back for analytics and monitoring// ...

  }

});

observer.observe({entryTypes: ["longtask"]});
Navigation Timing页面导航性能
Resource Timing子资源加载性能
Paint TimingFP/FCP
Element Timing自定义 LCP
Event TimingFID
Layout Instability APICLS
Long Tasks API长任务优化
Frame Timing慢帧优化

以用户为中心的指标

标准API的介绍,目的:如何检测应用的性能,如何去发现问题并有针对性地实施优化。对于用户的真实感受,我们还缺少一个可以量化的标准去衡量。🤔 如何更准确地评估用户的真实感受?

用户指标概览

从用户角度来看一个网页的加载过程:

  • 首先用户关注的一定是网页内容是不是呈现得足够快。如果页面加载太慢,用户往往会失去耐心而离开
  • 接着用户在看到关注的内容呈现之后,用户会下意识去操作页面。这个时候如果页面没有及时给出反馈,那么用户会察觉到我们的页面有延迟
  • 最后,如果网页内容在呈现过程中出现较大的抖动,比如页面突然啪的一下出来,或者视窗内内容发生了较大偏移,这个时候用户的感受往往是不愉悦的

因此我们在制定指标的时候,需要能够反映用户以上三个方面的感受,概括来说就是用户可感知的加载速度、页面的响应能力以及内容呈现的平滑度。

image-20210209161853018

绿色部分的两个指标,分别是首次内容绘制时间和最大内容绘制时间,反映的是页面的加载速度,以用户看到有效内容绘制为衡量标准。

蓝色部分有三个指标,分别是 首次输入延迟、页面可交互时间、主线程累计阻塞时间,反映的则是页面的响应能力。其中FID需要用户事件来触发,所以一般应用在生产环境。在实验室环境我们一般使用 TBT 或者 TTI 来代替。

橙色部分,CLS 指的是页面生命周期内累计布局偏移,反映的是页面内容呈现的平滑度,这个指标以分数的形式提供,可以在生产环境和实验室环境测试得到。

  • FCP 首次内容绘制时间 (First contentful paint)
  • LCP 最大内容绘制时间 (Largest contentful paint)
  • FID 首次输入延迟 (First input delay)
  • TTI 页面可交互时间 (Time to Interactive)
  • TBT 主线程累计阻塞时间 (Total blocking time)
  • CLS 累计布局偏移 (Cumulative layout shift)

FCP (First contentful paint) , LCP(Largest contentful paint)

FCP是首次内容绘制,LCP最大内容绘制

FCP相对简单,只要页面有内容出现,我们就认为达到了首次内容绘制时间

image-20210209162204831

而最大内容绘制时间需要不断跟踪页面的渲染情况。实际检测的时候,浏览器会把检测到的最大元素以事件的形式持续发给页面,所以最大内容时间的检测,一般以页面接收到的最后一个事件为主。

Largest Content

1. <img />

2. <svg><image/></svg>

3. <video poster=“poster.gif"></video>

4. <div style='background:url()' />

5. <div><text/></div>

image-20210209162222180

new PerformanceObserver((entryList) => {

 for (const entry of entryList.getEntries()) {

  console.log('LCP candidate:', entry.startTime, entry);

 }

}).observe({type: 'largest-contentful-paint', buffered: true});

目前最大内容可以是图片和文字,其中图片包括img标签、svg image、video 封面、背景图。

说明:Element Timing API 提拱了 LCP 的检测支持

TTI (Time to Interactive)

TTI 是页面可交互时间。ta的检测机制比较复杂,需要同时考虑主线程和网络情况。

图的上面是网络加载情况,底下主线程的任务分布情况,其中橙色代表的是长任务:web.dev/tti/

image-20210209162550545

  1. 首先以FCP作为起点,向右查找
  2. 找到一个 5s 的时间窗口,这个时间窗口内没有长任务, 并且网络请求不多于两个,图中灰色部分就是我们要找的时间窗口
  3. 以时间窗口的起点往回找长任务,这个长任务的结束时间就是页面可交互时间
  4. (如果没有长任务,则在FCP停止查找,此时认为FCP与TTI重叠)

FID (First input delay), TBT (Total blocking time)

FID 是首次输入延迟,代表的是用户对于页面响应度的第一印象。首次输入延迟指的是主线程首次接收到用户输入到开始响应的时间。输入延迟往往发生在主线程繁忙的时候,常见的场景是用户与页面交互时,主线程正在解析并执行一个巨大的JS,这个时候主线程无法响应用户。

image-20210209162720627

FID 主线程首次接收用户输入到开始响应的时间:

TBT 计算公式:

TBT=total(longtask)count(longtask)50TBT=total(longtask)-count(longtask)*50

任务取样区间为 FCP到TTI

TBT 是主线程累计阻塞时间,在实验室环境一般作为FID的替代指标。计算规则 取FCP到TTI之间的所有任务,累计长任务超出50ms的部分。

new PerformanceObserver((entries, observer) => {

 const firstInput = entries().getEntries()[0];

 const inputDelay = firstInput.processingStart - firstInput.startTime;

 observer.disconnect();

}).observe({type: 'first-input', buffered: true]});

FID 可以通过Event Timing来收集。

CLS(Cumulative layout shift)

CLS 累计布局偏移。视窗内可见元素的起始位置发生变化,就是发生了一次布局偏移,累计布局偏移则需要把所有非预期的布局偏移分数累加。

布局偏移分数 = 影响范围分数*位移分数

影响范围分数=影响范围(红色部分)/视窗面积

image-20210209163013696

位移分数=位移(紫色箭头)/视窗高度

  • Impact Fraction: 0.75
  • Distance Fraction: 0.25
  • layout shift score: 0.75*0.25=0.1875
let cls = 0;

new PerformanceObserver((entryList) => {

 for (const entry of entryList.getEntries()) {

  if (!entry.hadRecentInput) {

   cls += entry.value;

  }

 }

}).observe({type: 'layout-shift', buffered: true});

Web Vitals

  1. Web Vitals 的提出,是希望为应用性能提供统一的度量标准
  2. Core Web Vitals 是Web Vitals 最核心的部分,包含 LCP、FID、CLS三个指标
  3. ⚠️谷歌计划在2021年将 Core Web Vitals 列为网页排名算法中新的因子

image-20210209163050539

为了简化指标的采集,谷歌也提供了web-vitals库。Core Web Vitals,浏览器对其的支持还不完善,目前仅在最新的Chromium支持比较完备。浏览器支持情况 github.com/GoogleChrom…

import {getCLS, getFID, getLCP} from 'web-vitals';

getCLS(console.log);

getFID(console.log);

getLCP(console.log);

getFCP(console.log);

image-20210209163401995

最新的Devtools也增加了对Web Vitals的测试支持

打开一个空白页,使用F12打开开发者工具,选择performance面板

接着勾选截图和web vitals选项,开始录制

输入测试url,等待加载完成,停止录制

image-20210209163609200

image-20210209164409422

可以看到,最新的devtools

  • web vitals、long tasks都有了独立的窗格
  • LS 布局偏移
  • 时间线上,增加了LCP指标等

举个政采云的前台模型衡量指标来说明

juejin.cn/post/688758…

image-20210219105701122

image-20210219105924190

image-20210219105756280

image-20210219105808432

如何做性能优化

一般来说,用户可以感知的性能包括加载速度、响应能力 动画流畅性 能耗 内存占用等。对于能耗和内存占用,在web性能优化时没有特别好的技术手段,因此最起码的,我们要做到让手机不发烫、应用不奔溃。

image-20210209170812892

常用的优化手段

一般来说 缓存技术和预加载技术是性能优化最有效最直接的手段。除此之外,在不同的场景使用不同的渲染方案,也是常用的场景化优化手段。

  • 缓存技术

  • 预加载技术

  • 渲染方案

    image-20210219110001133

优化原则

  • 网络是不可靠的,尽量避免或提前
    • 如果能解决网络的问题,也就解决了性能的大部分问题
  • JS 是单线程的, 利用 Worker 并行
    • 在浏览器环境可能是Web Worker, sw,在端上使用性能更好的js worker
  • 开发端的能力, 极致优化
    • 利用服务端发起请求并渲染数据;客户端可以提供离线能力、以及 JS Worker
  • 在真实环境上测试性能:
    • 举一个v8的例子:v8在之前使用基准测试来度量性能,导致出现了一些在真实场景下没有任何帮助,甚至起到反作用的优化。可见我们在真实环境上测试性能的重要性
2. 缓存技术

缓存主要有CDN、浏览器缓存、应用离线包。

1.通用优化:
  • 使用CDN加速静态资源
  • 合理设置缓存时间 Cache-Control
  • 避免注册unload以影响前进后退缓存
2.前端最佳实践
  • 使用异步的Cache API/IndexDB,
  • Cache API主要存储HTTP请求,其他存储IndexDB
  • 尽量避免同步的 LocalStorage, ~5M
3.基于端的优化
  • 提供离线包,提前下发资源
  • 进一步考虑将离线包的资源预置进HTTP Cache
  • 进一步考虑主文档、关键路径资源预置到Memory Cache

image-20210209171149321

浏览器缓存比较多,其中

  • V8 CodeCache是字节码缓存, 可以大大减少JS解析、编译的耗时
  • BFCache: 用来缓存整个页面的状态,主要应用在前进后退导航、预渲染
  • Network Cache: 网络相关的缓存,如DNS缓存
  • 虚线部分是前端缓存:indexdb cookie local storage 等
  • 除此之外,还有浏览器使用最广泛的缓存HTTP Cache,内存缓存等
  • 其他浏览器缓存: 如图片解码数据,可以在惯性滚动及时把解码数据绘制到屏幕
  • 其他:
3. 预加载技术

预加载技术主要是标准定义的Resouces Hints和Preload。其中 Resources Hints包括 dns-prefetch, preconnect, prefetch, or prerender;Preload不在Resources Hints的定义里面

<link rel="dns-prefetch" href=“//example.com">

<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>

<link rel="prefetch" href="//example.com/next.html" as=“document" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">

<link rel="prerender" href="//example.com/next-page.html">

<link rel="preload" href="/styles/other.css" as="style">

preload prefetch的区别

  1. preload 用于预加载当前页面的关键资源
  2. Prefetch 预加载的是下一个页面的资源

prerender

  1. 预渲染会加载文档及子资源, 因此只预加载用户最大几率访问的页面
4. 渲染方案

常见的web渲染方案,按照渲染的环境和时机,可以分为四大类,分别是SR CSR SSR 以及在阿里业务大量使用的NSR。

  • 静态渲染 Static Rendering (SR)
  • 前端渲染 Client Side Rendering (CSR)
  • 服务端渲染 Server Side Rendering (SSR)
  • 客户端渲染 Native Side Rendering (NSR)

每种渲染方式都有其适用范围。参考:Rendering on the Web developers.google.com/web/updates…

SR VS CSR VS SSR VS NSR

SR:SR 编译阶段就生成好html结构。页面加载之后就可以直接进行渲染,性能最好,一般只能用在静态页面上。

image-20210209172211100

CSR:CSR 是最常见的渲染方式之一,广泛在SPA应用使用。CSR 通常在前端发起请求,在数据返回时使用JS渲染出HTML。在合理进行代码分包的前提下,其性能主要取决于网络和设备性能。在中低端设备和弱网环境下性能往往较差。

image-20210209172252555

服务端渲染SSR

通常在服务端直接渲染出HTML的方式一般都可以认为是SSR

image-20210209172504937

  1. 传统SSR使用PHP、Java等服务端语言结合后端模板来生成HTML结构,在前后端分离的大背景下,这种渲染方式已经不是主流。
  2. 主流的服务端渲染,使用的是前后端同构的方案, SSR with Rehydrate
  3. 比CSR相比,首屏性能和可交互时间更短,在低端设备和弱网情况下表现也更好。
  4. 较长的首字节时间,SSR渲染会增加服务器成本, 可以考虑增加一层缓存
NSR
  1. NSR 可以看作客户端的SSR,原理是把 SSR 放在服务端的工作放到端上来执行, 另外也配合客户端的离线资源和数据预取来进一步提升性能
  2. NSR可以把WebView的初始化、框架JS的执行与数据请求和渲染并行,大大缩短首屏时间,NSR在UC信息流、手淘会
方案对比

每种渲染方案都有一定优势,也有其局限性和缺点,我们需要根据实际场景来选择合适的渲染方案。

SRCSRSSR with RehydrateNSR
简介编译阶段生成HTML结构所有逻辑在前端完成, 最常见的SPA在服务端渲染首屏,在前端完成事件绑定客户端的SSR, 可以提前缓存资源和发起请求
优势👍 TTFB/FCP/TTI 👍 流式渲染👍 动态性 👍 TTFB👍 动态性 👍 首屏快👍 动态性 👍 缓存/并行
缺陷👎 动态性👎 TTI >>FCP 👎 流式👎 TTFB/TTI 👎 服务器成本👎 架构复杂 👎 需要端能力支持
适用场景博客、文档端外投放 移动设备/弱网端内投放
前端性能检测的两种方式

image-20210219105246213

image-20210219105345383

总结:

SR性能最好,一般只用在静态页面上

CSR的性能则取决于设备性能和网络状况,弱网、中低端设备性能很差

SSR with Rehydrate 利用服务端良好的网络和性能大大提升了首屏性能,在低端设备也有较好表现。适合作为通用方案投放在端外

NSR 利用端的缓存和数据预取能力,使得应用初始化与首屏渲染可以并行,是除SR之外性能最好的渲染方式。另外由于是在端上渲染,没有额外增加服务器预算。

其他优化手段

移动端的场景,WebView复用可以大大减少WebView的初始化时间

在一些很难优化的场景,使用人文关怀:苹果手机不是性能最好的,但是体验却是最好的

关于如何优化前端性能的其他资料:Google、百度一搜一大堆一大堆的,就不附上没用的链接了

性能监测工具

如何使用 Timeline 工具:developers.google.com/web/tools/c…

任务指什么?

了解任务的定义

  • 如图,火焰图最顶端灰色的矩形,就是在主线程执行的一个个的任务
  • 任务是一个个的工作单元,可以是js执行、html解析、样式计算、排版等
  • 任务右上角带有红色三角形表示的是超过50ms的长任务

image-20210209194440310

背景知识,关于主线程

现代浏览器采用多进程架构,一般分为Browser/UI进程、Render/Web进程

Chrome的主线程

在Browser进程,UI线程

在Render进程,Blink主线程

Lighthouse

Llighthouse的工作机制,Lighthouse与浏览器使用Devtools协议通信。

image-20210209194657944

Lighthouse 关注四个组件:

  • Driver: Devtools协议的封装,通过协议可以对页面实现导航、执行脚本、监听网络等各种操作
  • Gatherers: 日志收集器,收集 trace、网络事件、页面数据等各类日志
  • Audits: 检测项目,对日志进行分析,返回检测结果
  • Report: 按各个检测项配置的权重计算得分,输出测量的指标数据和优化建议
使用 Lighthouse测试应用页面性能

Lighthouse 是一个开源的自动化工具,用于改进网络应用的质量。 它可以作为一个 Chrome 扩展程序运行,或从命令行运行。 提供一个要审查的网址后,它将针对此页面运行一连串的测试,然后生成一个有关页面性能的报告。

通过生成的性能报告, 会给出一些建议用于提升应用的性能

分为五个部分进行统计并给出打分,分值越高越好。五个部分分别为

  • 性能
  • 无障碍
  • 最佳体验
  • SEO
  • PWA

每个部分会给出检测规则对应的问题和改进意见。

  • 移动端有很多H5业务
  • 需要在真实环境上测试性能
  • Lighthouse在移动端支持不足

所以各个公司对Lighthouse进行扩展来满足业务诉求:

美团的性能检测/测试

  1. RAPTOR: Raptor是面向基础设施和端到端应用程序的监控平台
  2. CAT:CAT 分布式实时监控平台
  3. FE GUARD:一套前端线上质量监控系统,致力于保障系统的稳定性、健壮性
  4. Falcon系统,Avatar系统等

政采云百策juejin.cn/post/688758…

业界还有很多优化方案,不一一列出

阿里的性能监控/测试

  1. 实验室测试:lighthouse webpagetest
  2. 线上监控: Chrome UX Report(CrUX) 阿里云的应用实时监控服务arms、uc的岩鼠 yanshu.effirst.com/ 、ARMS cn.aliyun.com/product/arm…
  3. 开发者工具: Chrome DevTools, React DevTools、岳鹰云真机yueying.effirst.com/index

image-20210209195313312

  1. 连接真机: 对接Android设备, Lighthouse连接到真机设备
  2. 支持阿里系应用: 覆盖阿里系大部分应用, Lighthouse测试应用内的页面
  3. 分析能力可扩展: 自定义的分析能力沉淀到检测项目市场, 供业务同学配置使用
  4. 分析方案可组装: 基于检测项市场,业务同学可以通过组装audits来形成新的分析方案
  5. U4 内核私有指标 T2、内置首屏性能优化方案

image-20210209195455641

LAAS:Lighthouse as a Service

image-20210209195527463

APP Mode: 移动端的页面, 阿里系应用(U4 应用)、Android Chrome

Headless Mode: 传统PC页面、H5页面

云测平台: 提供海量真机

前端搞起来[1] 前端搞起来[1]扫码关注xiaoyuanlianer666

小圆脸儿: 公众号:小圆脸儿(xiaoyuanlianer666)、掘金:小圆脸儿。