正文如下
本文是第十八届 - 前端早早聊性能优化专场,也是早早聊第 123 场,来自 阿里 UC-海愚 的分享。
我是来自 UC 内核团队的林洁伟,海愚是我的花名。今天我将分享的主题是如何重新认识性能优化及其度量方法。
主题分为三个部分,第一部分介绍性能优化技术及标准的发展。第二部分介绍以用户为中心的指标,最后我会结合一些经验讲讲如何做性能优化。
在开始之前我们先来了解一些术语:
- PWA 即渐进式的 web 应用开发,旨在增强 web 能力,缩小与原生应用的差距,并创建以及类似的用户体验。
- Lighthouse 是一款自动化测试工具,用于测试页面的性能并提出优化建议。
- SSR 即服务端渲染的,在服务端请求数据并组成 html 的渲染方式。
- NSR 可以认为是跑在客户端的 SSR
- Rehydration,俗称“注水”,指的是复用服务端渲染生成的 dom 结构及数据,在前端执行事件绑定逻辑来启动页面的一个过程。
优化技术及标准的发展
优化技术的发展
首先给大家看看过去近 20 年来性能优化的一个发展情况,可以看到散落在时间轴上的技术实践包含了方法论、测试工具、网络优化、解决方案以及指标等各方面。
我们看到最早的指导思想来自于 2007 年雅虎的 34 条军规,侧重于性能最佳实践。随后谷歌在 2015 年提出的 real 性能模型,就从方法论层面直接量化的性能的标准。
测试工具方面:分别有 yslow,web page test,page speed,lighthouse。
网络的优化:网络的优化主要体现在协议的不断升级。2009 年谷歌针对 HTTP 存在的连接无法复用,对头阻塞等多个缺陷问题,开始实验 SPDY 协议,SPDY 后来演进为我们现在使用的 HTTP2 标准,HTTP2 使用多路复用,二进制针头压缩等技术,极大的提升了性能,但还是存在一些问题。谷歌在 2012 年为了继续优化网络性能,推出了 QUIC 的初始版本,QUIC 是一种基于 UDP 的多路复用和安全传输,最终在2018年 HTTP over QUIC 也就是基于 quic 的的HTTP 协议,正式确定为HTTP3。目前谷歌和 Facebook 已经在生产环境率先使用了 HTTP3协议。
我们接着看解决方案方面,2010 年 Facebook 出 BigPipe 技术,这是一种动态网页加载技术,可以有效的提升首屏性能时间。接着在 2016 年,谷歌在 I/O 大会提出 PWA 概念,希望通过增强 web 的能力,全面提升外表应用的性能。随后在 2017 年 PWA 推广落地,同年 AMP 推出并广泛应用在移动端网页,AMP 和 PWA 也开始融合使用,可以看出性能解决方案从追求更快的加载到如今的追求 native 体验的一个演进。
我们看到时间轴的最后一部分,是谷歌在今年提出的 Web Vitals,Web Vitals 只是一项倡议,旨在为开发者提供统一的性能度量标准。可以看到过去近 20 年的一个技术发展都有谷歌的身影。谷歌作为 web 技术的主要用户,深刻的影响了 web 技术的发展。
接下来我们会重点介绍 real 性能模型及 pwa 这两部分内容。
RAIL 模型
首先是 RAIL 模型,当我们做性能优化时,我们往往需要一个明确的指引来告诉开发者应该优化什么,怎么优化以及优化的目标,或者说我们需要一个标准来告诉开发者用户的原理性能到底意味着什么。基于这个背景,chrome 团队提出了 RAIL 模型,简单的来说,RAIL 模型提供的是一个思考性能问题的方法论,他将用户体验分解为几个关键的动作,如点击滚动以及加载,RAIL 模型为这些动作也制定了相应的性能目标。
我们看来看一个用户访问页面的过程,用户访问一个页面一般都要经历加载、动画与页面交互以及空闲等几个过程,RAIL 代表的就是 web 应用生命周期的这 4 个不同的方面。
首先是 Response,代表的是页面对用户操作的一个响应能力。如果用户点击了一个按钮,页面需要在 100 毫秒内给出反馈,用户才不会有延迟感。这里 100 毫秒的目标来自于一项人机交互项目的研究成果,另外考虑到主线层也会执行其他任务,模型要求任务需要在 50 毫秒内完成。
Animation 指的是动画过程,目标是保证动画的一个流畅性。一般来说我们需要达到 62ps 的增率,才能保证动画的流畅性。这就要求每帧动画需要在 16 毫秒内完成。另外由于浏览器券也需要时间,因此模型规定应用需要在 10 毫秒内产生。
第三个是 Idle,Idle 指的是主线成了一个空闲状态,目标值是最大化,主线成了一个空闲时间。为什么要这么做?因为我们前面提到我们需要在 100 毫秒响应用户,如果我们主线层很繁忙的话,我们就没办法做到 100 毫秒去响应用户。所以结合前面的目标,我们的模型要求,跑在主线层的延时任务,最大的时间不能超过 50 毫秒。
最后一个是 Load,代表的是页面的加载速度,目标则需要根据网络状况和设备状况来设定,模型提供了一个参考目标。在 3G 网络中等设备在 5 秒内达到用户可交互。
前面我们提到事件处理需要在 50 毫秒完成,延伸任务也不能超过 50 毫秒。这里为什么是 50 毫秒?
我们解释一下,我们看到主线程的一个任务调度情况,主线程除了会处处理用户事件,也会有其他任务执行,这些任务会占用部分时间,所以事件处理会排在后面执行。
根据前面的目标,我们需要在 100 毫秒对用户事件作出响应,结合图上的任务执行情况,在 100 毫秒内我们需要执行两个任务,分到每个任务就是 50 毫秒,因此我们也把超过 50 毫秒的任务定义为长任务。
PWA
Web 应用在用户体验上往往比不上 native 应用,首先 web 应用往往依赖网络来加载内容,存在着弱网环境加载慢,离线情况无法访问的问题。其次,外表应用也无法做到像 native 一样添加到桌面上,用户往往需要通过输入 URL 来获取内容。除此之外,native 应用的部分能力在 web 也是缺失的,比如说消息推送能力,native 应用虽然体验好,但也存在着一些问题。
比如 native 应用的开发成本较高,动态性也较差,用户在使用前也需要去下载安装,基于这些背景,谷歌在 2016 年提出 PWA 的概念,希望通过增强 web 的能力来缩小与 native 应用的差距,并提供与其媲美的用户体验。我们看到 PWA 有几个重要的特性,第一个是 Service Worker,Service Worker 可以看成是一个可编程的网络代理,他提供了离线化的支持,其中就包括缓存和预加载,Service Worker 也是其 PWA 的特性实现的基础。
App Manifest 用来定义外部应用的表现和行为,包括添加到桌面的图标,以及全屏状态下的闪屏动画。
第三个是 Push and Notification, 为 web 应用补齐了消息推送和接收的能力。
最后一个是离线缓存,离线缓存借助的是 Service Worker的离线化能力,使得用户在离线的情况也能使用部分功能,PWA 也包含了其他特性,有比如说读取设备的状态,通过蓝牙分享的最终的目的都是希望通过渐进增强的方式来逐步达到 native 应用的体验。
目前主流的浏览器也都不同程度上支持了 PWA,国内外的一些网站也都进行了 PWA 实践,比如说阿里巴巴、京东等,这些网站在应用 PWA 之后也得到了一些可量化的收益。根据谷歌分享的案例,京东印尼站在使用 PWA 的缓存桌面安装消息推送的能力之后,转化率提升了 53%。
标准组织
我们都知道标准的制定离不开标准组织,性能标准也不例外。新闻领域有两个重要的组织,一个是 1994 年成立了 w3c,w3c 是 web 技术领域最具权威和影响力的国际中立性标准机构。
另外一个就是 2010 年,w3c 成立了 web 性能工作组,web 性能工作组的目标就是制定衡量 web 应用性能的方法和API。
我们接下来了解一下 web 性能工作组织制定的一系列 API 从这张图可以这些API大致分为三类
第一类是框架类的 API 主要包含最左边部分,high resolution time,还有一个是 performance timeline,提供的是高精度时间接口,以及查询查询性能数据的接口。
第二类是度量类的 API 用来检测页面生命周期内不同方面的性能数据,对应中间的部分。
第三类是各种优化策略的 API 用来改善页面性能,主要是最右边部分,提供的能力,包括页面可见性,任务调度预加载等能力。
首先我们看一下 performance timeline,performance 他们主要包含三个部分:
第一部分是高精度时间的接口,包括 performance,对象上面的 NAO 方法。
第二个是 performance time 来提供的查询性能接口的主要 API 比如说 getEntries 以及 getEntries byType 、byName两个接口。
最后 performance timeline 也定义了两个重要的对象,这两个重要的对象是我们检测性能的一个基础对象。其中 performanceEntry 是其他 Entry 的一个基类。我们通过 getEntry 可以看到浏览器返回了一些 Entry 列表,这里所有的 Entry 列表都继承于 PerformanceEntry。
另外一个是 PerformanceObserver,用来监测基于事件的指标,我们可以看一下 API 的一个使用情况。
接着是 Navigation timing,定义的是文档,导航过程中完整的性能度量及文档,从发起请求到完成加载的各阶段号时,其中页面的导航性能可以通过 performance 的 timing 接口来获得。
Navigation time 则表示导航的一个类型。目前有 4 个类型,分别表示的是导航刷新,前进后退以及预渲染,从 navigation 的 timing 中,我们可以看到 navigation timing 复用了 resource,resource timing 的时间走,对应的就是图中的部分。
接下来是 Resource timing,记录的是子资源的请求到加载完成的各阶段耗时,子资源的性能数据可以通过 getEntriesByType 接口来查询,传入的类型为 resource。
关于这个 API 我们需要注意的一个点是对于跨域资源的性能数据,我们需要正确返回 Time-Allow-Origin 请求头,子资源的性能才能被页面获取到。
我们再来看一些比较新的 API。Paint Timing,用来测试两个指标,一个是 FP,另外一个是 FCP,分别是首次绘制和首次内容绘制,计算也比较简单,通过前面 observer 的接口来监听。
另外一个比较新的接口是 Event timing。
Event Timing 提出的背景是我们需要跟踪页面输入事件的处理延迟,目前处于一个草案阶段,这个 API 目前主要用来计算 FID 这个指标,算法也是比较简单,是把开始处理时间和首次输入接收到的时间做一个相减。
接下来是 Frame timing,Frame timing 提供的是记录慢帧信息的能力,也是一个草案阶段的标准,其中帧的定义是两个 vsync 之间在 60 赫兹的屏幕刷新率下,慢帧的时处理时间上限是 16.6 毫秒,使用上跟前面的方式保持一致。
最后一个是长任务 API 用来监控主线程的一个长任务状态,我们都知道常任务会阻塞,主线层到页面无法快速响应用户输入,所以对于长任务,一般的优化手段是合理拆分成子任务来优化。
我们稍微总结一下,我们使用 Navigation Timing 获取的是页面的导航性能,Resource Timing 用于获取子资源的加载性能,中间加粗的 4 个部分,测试的是我们接下来要介绍的用户指标,最后是长任务 API 和 Frame Timing,提供了我们应用需要关注的优化信息。除了提供度量 API 外表性能工作组也提供了一系列优化策略的API页面可见性,任务调度,Resources Hint,这里不再一一展开。
以用户为中心的指标
通过前面标准API的介绍,我们知道了如何检测应用的性能,也知道如何去发现问题,并有针对性地实施优化。但是对于用户的真实感受,我们还缺少一个可以量化的标准去衡量,如何更准确的评估用户的真实感受。
用户指标概览
我们来看看一些最新的指标,首先我们从用户的角度来看,一个网页的加载过程,用户首先会关注的是一定是网页内容是不是呈现的足够快,如果页面加载太慢,用户往往会失去耐心而离开。接着用户在看到关注的内容呈现之后,用户会下意识去操作页面,这个时候如果页面没有及时给出反馈,那么用户会察觉到我们的页面有延迟。最后如果网页内容在呈现过程中出现较大的抖动,比如页面突然啪的一下出来,或者视窗内容发生了较大偏移,这个时候用户的感受往往是不愉悦的。因此我们在制定指标的时候,需要综合考虑用户以上三个方面的感受,概括来说就是用户可感知的加载速度,页面的响应能力,以及内容呈现的平滑度。
我们这里介绍的 6 个指标,就包含了以上三个方面的考量。其中绿色的部分分别是首次内容绘制时间和最大内容绘制时间。这两个指标反映的是页面的加载速度,以用户看到有效内容绘制为标准。蓝色部分只包含三个指标,分别是首次输入延迟,用户可交货时间以及主线程累计阻塞时间,反映的只是页面的一个响应能力。其中 FID 需要用户输入来触发,所以一般应用在生产环境,在实验室环境我们一般使用 tvt 和 tti 来代替。最后橙色的部分,cls 指的是页面生命周期内累计布局偏移,反映的是页面内容呈现的一个平滑度,这个指标以分数的形式提供,可以在生产环境和实验室环境测试得到。
我们先看第一组指标,FTP 是首次内容绘制,LCP 是最大内容绘制,FTP 相对比较简单,只要因为有内容出现,我们就认为达到了首次内容绘制的时间,而最大内容会诊时间需要不断跟踪页面的渲染状况。实际检测的时候,浏览器会把检测到的最大元素以事件的形式持续发给页面,所以最大内容时间的检测,一般以页面接收到的最后一个事件为主。目前最大内容可以是图片和文字,其中图片就包括 image 标签,SVG image,video 封面、背景图。最后说明一下,LCP 的一个检测是通过 Element Timing API 来提供支持,使用的也是通过监听性能事件的一个方式。
TTI 页面可交付时间,这个指标的检测比较复杂,需要同时考虑主线程和网络的情况。
我们的图的上方表示的是网络请求情况,下底部是主线层的一个任务分布,首先以首先我们会从 FTP 作为起点向右查找,我们先会找到一个 5 秒的时间窗口,这个时间窗口内没有常任务,并且网络请求不多于两个。我们可以看到图中灰色的矩形部分就符合我们这个要求,找到这个时间窗口之后,我们以这个时间窗口的起点往回走,直到找到最最近的一个长任务,长期任务的结束时间,我们定义的页面可交互时间,接下来我们看看 FTP 和 TVB,FTP 是手机用户输入延迟,tpt 就是主线程累计累计的阻塞时间,happy fid 指的是主线程首次收到用户输入,到开始响应了这部分时间,我们可以看到图上有一个比较长的任务,然后是用户事件在任务的前方发生,然后浏览器开始处理,只是在长任务结束之后,速度延迟主要发生在主线层繁忙的时候,常见的场景就是用户跟页面交互时,主线程正在解析并执行一个巨大的 GS,这个时候主线程是无法响应用户的。
我们接下来看一看 FID 的一个计算方式,FID 一般作为 for 的替代指标在实验室测试,它的计算规则是取 FTP 到 TCL 的之间的所有任务,累计长任务超过 50 毫秒的部分,用数学的方式表示就是所有长任务之和减掉常任务的个数乘以 50,这个是首次输入延迟的一个计算。
最后我们看一下一 CLS 是累计布局偏移,视窗内可见元素的起始位置发生变化,我们就认为发生了一次布局偏移。如我们这个图上所示的文本节点,我们来看一看单色布局偏移分数的一个计算情况,布局偏移分数等于影响范围,分数乘以位移一分数,什么是影响范围?分数影响范围分数就是我们的元素的影响范围。图中红色的部分和视窗面积的一个比值。位移分数,位移高度比视窗高度。这里图主要是只是箭头的部分,然后浏览器可以通过 Layout Instability API 会这个指标提供支持。
接下来我们看看 Web Vitals,Web Vitals 的提出的背景是谷歌希望为应用性能提供统一的度量标准,其中 Core Web Vitals 是 Web Vitals 最核心的部分,包含 LCP,FID 以及 CLS 这三个指标。Core Web Vitals 也为这些指标设定了性能目标。另外关于 Core Web Vitals,值得注意的是谷歌计划在 2021 年将 Core Web Vitals 列为网页排名算法中新的因子。为了简化指标的采集,谷歌也采也提供了 Web Vitals 库,开发者只需要引入模块配置,数据上传就可以完成指标的采集。
另外一个我们需要注意的是 Web Vitals 是刚刚出来不久,浏览器对其的支持也不完善,目前只仅在最新的 chromium 支持比较完备。
最新的 Devtools 也增加了对 Web Vitals 的支持。这里我们通过一个录制的视频简单看一下
首先通过 F2 打开 Devtools,选择 performance 面板,勾选 Web Vitals 以及录屏。接下来输入 URL,在页面完成加载的时候,停止录制,可以看到最新的 Devtools 性能面板,增加了很多新的内容。
这里我用红色的圆圈标出来,可以看到最新的 Devtools,提供了 Web Vitals, long task, 都有了独立的 Pane,布局偏移,也帮我们标了出来。时间线上我们可以看到,多了 LCD 指标。
如何做性能优化
最后部分我们看看如何做性能优化。
性能指什么
一般来说用户可以感知的性能,包括加载速度、响应能力、动画流畅性、能耗以及内存占用等。对于能耗和内存占用,在外部性能优化使我们没有特别好的技术手段去优化它。因此对于这两个性能,我们最起码要做到的是让手机不发烫以及让应用不崩溃。
常用的优化手段
看看常用的一些优化手段,一般来说缓存技术和预加载技术是性能优化最有效也最直接的一个手段,在不同的场景使用不同的选择方案,基于场景的常见优化手段。
我们先看看一个优化的几个原则,第一个是我们要记得网络是不可靠的,如果我们可以解决网络的问题,我们也就解决了性能的大部分问题。第二个是 JS 是单线程的,我们应该利用 Worker 来并行,其中在浏览器环境,Worker 可能是 Web Worker 或者是 Server Worker,在端上我们可能会使用性能更好的 APP Worker。
第三点端的能力,这里就包括服务端和客户端,比如利用服务端发起请求并渲染数据的 SSR,客户端的能力,客户端可以提供离线化能力以及 JS Worker支持。
最后一个,我们需要在真实的环境上测试环境。这里举一个 V8 的例子,V8 在之前使用基准测试来度量性能,导致出现了一些在真实场景下没有任何帮助,甚至起到反作用的优化。所以我们的性能测试是最终都要在真实环境上面去衡量。
接着看我们的缓存技术,我们使用的缓存主要有 cdn、浏览器缓存以及应用离线包,浏览器缓存比较多,其中 v8 code cache 是字节码缓存,可以大大减少 js 的编译、解析耗时。
BFCache 用来缓存整个页面的状态,主要应用在前进后退导航,预渲染等场景。network cache,主要指的是 DNS 缓存等,网络缓存。虚线部分标出的只是我们前端长经常使用的缓存,包括 IndexDb、localstorage、Cookie,以及Cache Storage。除此之外,浏览器使用最广泛的还有 HTTP Cache,Memory Cache 等。
对于缓存的使用,我们通用的优化一般是使用 cdn 来加速静态资源,对我们的静态资源合理设置缓存时间,另外我们需要值得提起注意的是,我们要避免注册 unload 的事件,来影响页面的一个前进后退性的前端部分的最佳实践。
我们应该尽量避免使用同步的 localstorage,除了它的底层是对同步的,它在存储上面也有一些限制,一般是5M,应该尽可能地使用异步的 IndexDB,Cache API,其中 Cache API 主要用来缓存请求相关的资源,其他的资源我们一般可以放在 IndexDB 里面,最后基于端上的优化,我们可以在端上通过提供端上的离线包来提前下发资源,进一步的考虑我们可以将主文档关键的 JS 资源直接内置到 memory cache,因为我们的内存访问是最快的。
预加载技术主要是标准定义的 resources hints 以及 preload,其中 resources hints包括 dns-prefetch,preconnect 以及 prefetch。preload 是单独定义的,不在 resources hints 里面的定义。
这里我们需要注意的是 preload 和 prefetch 的一个区别,preload 一般用来预加载当前页面的关键资源, prefetch 只用于加载下一个页面的资源,这是其中最关键的一个区别,prerender 是页面预渲染,他会加载文档以及子资源。因此我们一般不会大大规模的使用 prerender,我们只会在用户最大几率访问的页面上面使用。
我们再来看看常用的渲染方案。按照渲染的环境和时机可以分为 4 个大类,分别是静态渲染、前端渲染、服务端渲染以及客户端渲染。
我们来看一看每种渲染方式的一个渲染流水,首先是 SR,SR 在编译阶段就生成好 html 结构,在页面加载完之后就可以直接渲染的一种方式,可以看到它的性能一般是最好的,而且也只能用在而且只能用在静态页面上。
CSR 只是我们最常见的前端渲染方式,CSR 是把所有的计算逻辑,包括数据请求,数据渲染全部放在前端来执行的一个渲染方式。一般它的性能主要取决于设备的网络情况以及设备的性能。
我们再来看看服务端渲染的,通常在服务端直接渲染出 html 的方式,都可以认为是 ssr,传统 ssr 使用的是 PHP 以及 Java 等语言,结合后端模板来生成的 html 结构,在前后端分离的大背景下,这种渲染方式已经不再适用。
主流的服务端渲染,我们今天要讲的 ssr with rehydrate。使用的是前后端同构的方案。ssr with rehydrate 它的数据请求和首屏的数据请求和数据拼装都发生在服务端,所以页面在加载文档之后可以很快渲染出来。但是它有一个缺点就是它需要在前端重新执行一遍,这个时候会导致页面的响应时间会偏长。和 CSR 相比,ssr with rehydrate 的首屏性能和可交互时间更短,在低端设备和弱网的情况表现也更好,因为服务端渲染也是需要时间处理,所以这里也会引入一个首字节时间偏长的问题。
另外一个我们需要考虑的是 SSR 渲染是在服务端,它会增加服务器的成本,所以一般我们的 SSR 都会在后端加一层缓存。
NSR 可以看作是在客户端运行的 SSR,原理是把 SSR 放在服务端的工作放到端上来执行。另外也配合客户端的一些资源和数据预取来进一步提升性能。从我们这个流水线图可以看到,NSR 数据请求,首屏数据请求和数据线上与 webview 的一个初始化和框架 JS 初始化并行了起来,大大缩短了首屏时间。
这种方式在UC线信息流和手淘会场等业务大量使用。
当然我们也要看到每种现场方式都有一定的优势,也有其局限和缺点。我们需要做的是根据实际场景来选择合适的宣传方案。SR 的性能最好,但他有一个致命的缺陷,它只能用在静态页面线的上面。CSR 的性能则取决于设备性能和网络状况,弱网和中低端设备的性能较差。SSR 只利用服务端良好的网络和性能,大大提升了首屏性能。在低端设备也有较好的表现。SSR 这种这种渲染方式,可以作为通用的优化手段。
一般我们会在端外投放 SSR 的页面,NSR 利用端的缓存和数据预取能力,使得应用初始化跟守平线可以并行,是除了 SR 之外性能最好的选择方式。另外由于是在端上渲染的,对于服务器成本没有额外的增加。
其他的优化手段。比如说在移动端的场景,我们可以复用 WebView 来大大提减小 WebView 初始化时间。另外在一些很难优化的场景,我们可以使用一些我们可以给到用户一些反馈,通过一些人文关怀来做到将用户感觉性能也不是太差。
我们也可以看到苹果手机在这方面做的比较好。苹果手机不是实际性能最好的,但是它的表现性能却是最好的。我们再看看 UC 信息流正文页的一个展开实践,这个视频展示的是信息流正文页优化前后的一个对比,可以看到优化后的页面是做到了展开的效果,具体是如何做的?
我们先看看一些背景介绍,首先信息流的列表页使用的是为是技术,图文正文是正文页使用的是 h5 技术,从列表页点击到进入正文页,中间会有一个 300 毫秒的 WebView 进场动画,也就是我们这张图展示的一个交互。所以性能这种技术目标需要在 300 毫秒完成首屏渲染了,就是在动画结束之后,页面也要看到页面。另外在业务上,正文业除了在端内在端外也有投放的需求,所以需要考虑跨端跨平台。
我们再看看信息流在做优化时的一个技术策略的推演。
第一个问题是为什么信息流优化策略没有选择 weex,weex 在端内有比较好的性能优势,但它不是标准技术,端外的页面也需要单独优化。而 h5 天然跨端跨平台,也是一种标准技术,性能相对于 weex 不占优势,但优化的天花板可以很高,就是说我们的 h5 可以通过优化来达到更好的性能。
第二个问题是为什么没有使用 SSR?SSR 是用在端外,端内可以有更好的方案。这里就是我们后面要介绍的 NSR 渲染方案。
第三个问题,信息流,信息流团队为什么没有选择 PWA。PWA 有一个问题就是 Service Worker 的启动和保活成本很高,耗时大概在 100 毫秒到 1000 毫秒不等。
根据我们前面设定的技术目标,如果使用 PWA 的方案,我们无法做到大部分展开的目标,所以信息流最后的优化方案选择了选择了 NSR 渲染。
这里面有几个关键的一个技术。第一个是利用端的极限化,把所有资源都放到离线包,甚至更激进的主文档等关键资源预制到内内存。
另外一个是数据预取,数据一起是在列表页下的时候就去加载数据,通过前面这两个优化,我们基本就排除了网络网络不稳定带来的性能影响。
另外使用 NSR 的方案,我们前面看到 NSR 可以让页面的框架初始化和数据渲染并行,使得 WebView 在进场后页面也可以完成渲染。当然最后最后要做到极致优化,我们还需要对页面的页面进行彻底的瘦身,确保首屏使用的是最小的 js bundle。
我们看到信息流在优化过程中,技术方案从 CSR 变成了 NSR 这里带来一个这里带来一个工程化的问题,就是说原来前端只要一个 CSR 的 Bundle 包就够了,但是做了技术改造之后,我们需要同时支持 CSR,SSR 以及 CSR 不同方式的渲染,就要求我们一套代码构建出三个支持不同渲染方式的 JS Bundle。
所以这里这里对工程化的一个挑战就是怎么做到在优化性能的同时,也尽可能的降低研发成本。最后从信息流的优化,我们也可以得到一些启发。这里就用信息流同学的总结,可以看到做性能优化除了要有知识方面的储备,最重要的还是不要给自己设限。