【第1932期】2020前端性能优化清单之一

作者:陈隆德

前言

史上最长的参考资料。今日早读文章由京东@陈隆德翻译授权分享。

维C团(WecTeam)是京东旗下京喜事业部的前端技术团队,主要专注于前端工程化、Web性能优化、小程序开发、Severless、多端复用、可视化搭建等前沿技术研究,前端性能优化清单系列由团队成员陈隆德、龙朝忠、马雪琴、朱志玉集体翻译。

正文从这开始~~

简介

让2020年变得更...快些吧!这是一份年度前端性能优化清单,包含了当下创建web快速体验所需的一切。这份清单自2016年开始已经持续更新了5年。这份清单得到了LogRocket的大力支持,LogRocket是一个前端性能监视解决方案,可帮助重现错误并更快地解决问题。

web性能是一头狡猾的野兽让人难以琢磨和处理,不是吗?我们如何才能知道我们在性能方面所处的真正水平,以及我们的性能瓶颈到底是什么呢?它是巨大的JavaScript文件、缓慢的Web字体传输、繁重的图像、还是缓慢的渲染?是否值得去研究 Tree-Shaking、作用域提升、代码拆分,以及所有奇特的加载模式,包括交叉点观察器做懒加载、服务器推送、客户端提示、HTTP/2、service workers 或者说 edge workers?而且,最重要的是,我们该从哪里开始做性能优化,以及我们应该如何建立长期的关注性能的团队文化?

在过去,性能往往在开发初期时被忽略。性能优化通常会推迟到项目快结束时候,并最终简单归结为代码压缩,并行请求,静态资源化,或许还有一些对服务器config文件的微调。现在看来,性能优化这项工作已经发生了很大的变化。

性能不仅仅是一个技术上的问题:它会影响从 可访问性、可用性到搜索引擎优化的方方面面,并且如果我们把性能优化引入工作流程中,那么在设计和决策时就需要考虑对性能影响。性能必须不断地进行测量,监视和完善,但是网络的日益复杂性带来了新的挑战:那就是性能指标的跟踪,因为性能指标会因设备,浏览器,协议,网络类型和网络延迟不同而有很大差异(CDN,ISP,缓存,代理,防火墙,负载均衡和服务器配置都对web性能有着明显的影响)。

因此,如果我们要建立了一个包含性能优化所有要点的清单(从研发开始到网站最终上线),该清单会是什么样的呢?您会在下面找到一份(希望它是没有偏见的和客观的)* 2020年前端性能优化清单* — 它包含您可能需要考虑性能的场景和优化手段的简介,以达到快速的响应时间,流畅的用户互动,以及网站不会浪费用户的带宽。

内容目录

出发吧!

准备工作:计划和指标

时不时的小优化对于保持良好性能很有效果,但更重要的是:在头脑中明确性能目标(可衡量的目标),因为这将影响整个开发过程中我们所做的任何决策。下面有几种不同的性能指标模型,关于这些模型的讨论会比较主观--您只要确保在工作开始时设置自己的优先级即可。

01 建立性能优化的文化

在许多团队中,前端开发工程师都明确地知道那些常见的性能问题,以及使用何种加载方式能够解决这些问题。但是因为缺乏对性能优化关注的文化,每一项关于性能的决策都演变成了部门之间的PK,把组织分裂成1一个个孤岛。随着时候您就需要业务方的支持,如何获取支持呢?首先需要进行一个案例研究,或使用Performance API[1] 来证明[2] 性能如何提升他们关心的工作指标和关键绩效指标(KPI)。

如果开发/设计团队与业务/营销团队之间无法对性能优化的目标保持一致,那性能优化将无法长期维持。因此性能优化的工作需要关注客户服务和销售团队的常见投诉,研究高跳出率和低转化率的原因。探索性能优化如何帮助缓解这些常见问题,并根据与你交谈的利益方调整你的论点[3]

运行性能实验并测量结果 - 无论是在移动设备上还是在桌面上(例如,使用Google Analytics) 将帮助你用真实的数据为公司进行定制性的分析。此外,使用发布在WPO Stats[4]上的研究案例和实验数据,也可以帮助我们明确性能对业务提升的重要性,以及它对用户体验和业务指标的影响。然而,仅仅说明性能很重要是不够的 - 您还需要建立一些可衡量和可跟踪的目标,并随着持续跟踪相关指标。

怎么达到目标呢?Allison McKnight在她关于建立长期的性能优化文化[5]的演讲中,分享了一个全面的案例研究-如何帮助Etsy建立重视性能的公司文化(幻灯片[6])。最近,Tammy Everts也谈到了在小型和大型组织中如何在团队中培养关注性能的氛围[7]

Performance budget builder by Brad Frost and Jonathan Fielding’s Performance Budget Calculator can help you set up your performance budget and visualize it. (Large preview)

由Brad Frost的性能预算生成器和Jonathan Fielding的性能预算计算器可以帮助您设置性能预期并对其进行可视化。

02 目标:比你最快的竞争对手至少快20%

根据用户心理学研究[8],如果想让用户感觉你的web网站比其它竞品快,那您必须比它们快20%以上。研究您的主要竞争对手,收集它们在移动设备和台式机上的性能指标,并设置阈值以帮助您超越竞争对手。但是,要获取准确的性能指标并制定目标,请务必先通过研究分析来全面了解用户体验。然后,你可以根据90%的主要用户的反馈和经验来模拟测试。

你可以使用Chrome UX Report[9] (也叫CrUX, 一个现成的实际用户体验监控报告, 参考Ilya Grigorik的视频介绍[10] 和 Rick Viscomi的详情使用指南[11])或者Treo网站[12],一个由Chrome UX报告提供支持的实际用户分析监视工具。作为替代品,你也可以使用Speed Scorecard[13] (也提供对网站收入影响的评估)Real User Experience Test Comparison[14] 或者SiteSpeed CI[15] (基于综合测试)。

Treo Sites provides competitive analysis based on real-world data. (Large preview)

Treo Sites 根据实际数据提供网站竞争性分析

注: 如果你使用Page Speed[16] Insights或者Page Speed Insights API[17]。除了汇总数据,您也可以获取特定页面的CrUX性能数据。这些数据对于为 "落地页" 或 "产品列表" 之类的页面单独设置性能目标可能更有用。补充说明,如果您使用CI来测试性能预期,则需要确保您的测试环境与CrUX匹配,然后再使用CrUX设置性能目标(感谢Patrick Meenan反馈!)。

如果您想知道显示速度优先级排序背后的原因,或者您想要可视化来展示页面转换率下降、跳出率增加后者性能降低,或者您可能需要在组织中倡导基于真实用户体验的解决方案,Sergey Chernyshev已经开发[18]了(UX Speed Calculator)UX 速度计算器[19](一个开源工具),可以帮助你拟合数据并将其可视化,验证你的观点。

Just when you need to make a case for performance to drive your point across: UX Speed Calculator visualizes an impact of performanc on bounce rates, conversion and total revenue — based on real data. (Large preview)

在需要提高性能来说明您的观点时:UX 速度计算器基于真实数据,可以把性能对页面转化率、跳出率和总收入的影响用可视化的图标展示

收集数据,建立表格,以提升20%的性能设定你的目标(性能预算)。现在你有了可以衡量的目标来测试了。如果你把预算记在心里,试着把最小的有效载荷降下来,以获得一个快速的可交互时间,这样就是一个正确的性能优化方式。

需要一些资源来开始?

Jonathan Fiding的Performance Budget Calculator(性能预算计算器)[24]、Katie Hempenius的Performance Budget Calculator(性能预算计算器)[25]和Browser Calories(“浏览器卡路里计算”)[26]可以帮助创建性能预算(感谢Karolina Szczur[27]反馈)。

此外,可以设置带有报告构建大小的图形的仪表板,使性能预算和当前性能变得可视化。有许多工具可以实现:SiteSpeed.io仪表板[28](开源)、SpeedCurve[29]和Calibre[30]只是其中的一小部分,您可以在Perform.rocks[31]上找到更多工具。

一旦有了性能预算,就可以将它们与Webpack性能提示和Bundlesize[32]、Lighthouse CI、PWMetrics[33]或Sitespeed CI[34]结合到构建过程中,这样就可以在git合并请求(pull requests)时考虑性能预算,并在PR评论中提供评分历史。

要向整个团队公开性能预算,可以通过Lightwallet在Lighthouse中集成性能预算[35],或者使用LHCI动作来快速集成到 Github Actions[36]。如果需要自定义,可以使用WebPagetest -chart-API[37],这是一个接口API,用于根据WebPagetest结果构建图表。

不过,性能意识不应该仅仅来自性能预算。就像Pinterest(世界上最大的图片社交分享网站)一样,您可以创建一个自定义eslint规则[38],比如不允许导入依赖关系较重且会使构建产物明显膨胀的文件或目录。设置一个在整个团队中共享的"放心使用"包列表。

此外,还要考虑对您的业务最关键的用户操作。研究、讨论和定义关键操作的可接受时间阈值,并建立整个组织认可的“UX Ready”用户计时标记。在许多情况下,用户浏览和行为路径将涉及许多不同部门的工作,因此,根据可接受的时间进行调整将有助于支持或减少以后团队和部门间关于性能的讨论。确保增加资源和功能的额外性能成本是可见的和理解的。

另外,就像 Patrick Meenan 所建议的,在UX设计过程中就权衡加载顺序非常有用。如果您一早就确定页面中哪些组件比较关键,并定义它们应该出现的顺序,那就可以确定哪些组件可以延迟加载的。理想情况下,该顺序还将影响CSS和JavaScript导入的顺序,因此在构建过程中处理它们的顺序会变得更加容易。此外,在加载页面时(例如,当网页字体尚未加载时),请考虑在“中间”状态下的视觉体验应该是什么。

规划、规划、规划。在早期进行快速的“容易够得着的水果”似的性能优化可能很诱人,也是一个能快速取得成功的好策略,但是如果没有规划,没有切合实际的、为公司量身定制的性能目标,在长期的开发维护过程中就很难一直把性能放在首位。

首次渲染、首次有内容渲染、首次有效渲染、渲染完成时间和可交互时间之间的区别[39]@denar90

11-metrics-front-end-performance-checklist-2020

2020年初,新的性能指标将在Lighthouse v6中发布。不再推荐使用“首次有效渲染(FMP)”,并且再下个Lighthouse版本中引入最大内容渲染时间(LCP)和总阻塞时间(TBT)这两个指标。

03 选择正确的指标

并不是所有的指标都同样重要[40]。研究哪些指标对您的应用程序最重要:通常,它将由开始呈现界面中最重要的像素的速度以及为这些呈现的像素提供输入响应的速度来定义。下面这些知识将为您提供最佳的优化目标,以进行不断的正确方向的努力。再强调一点,定义体验的指标不是客户端加载时间,也不是服务器响应时间,而是实际用户感觉界面有多快。

什么意思?与其关注整个页面加载时间(例如,通过onLoad和DOMContentLoaded计时),不如按照用户的看法确定页面加载的优先级。这意味着你会着关注一组略有不同的指标。事实上,选择正确的指标是持续不断的过程。

根据Tim Kadlec的研究和Marcos Iglesias在他的演讲[41]中的笔记,传统的度量指标可以分成几组。通常,我们需要所有这些度量指标才能全面了解性能,但是根据您的特定情况,其中一些指标可能比其他更重要。

为了使性能指标这块拼图更完整,我们会在所有这些组中寻找有用的指标。通常,最具体和最相关的是:

Time to Interactive[44] (TTI)

布局已经稳定、关键的Web字体可见、并且主线程已经空闲下来可以处理用户输入的时间点-基本上就是用户可以与UI交互的时间标记。这是了解用户必须经历多少等待才能毫无延迟地使用网站的关键指标。

First Input Delay[45] (FID), 或者 Input responsiveness

从用户首次与网站进行交互到浏览器实际上能够响应该交互的时间。它很好地补充了TTI指标缺少的那部分:当用户实际与站点进行交互时会发生什么。一般仅用作RUM度量标准。有一个标准的JavaScript库[46],用于在浏览器中测量FID。

Largest Contentful Paint[47] (LCP)

这是在页面加载时间线中,标记已加载页面重要内容的时间点。假设页面中最重要的元素是在用户的视区中可见的最大元素。如果元素同时在可视区域的上方和下方渲染,只有可见部分被认为是相关的。目前在Lighthouse中,它是一个隐藏的指标,如果证明是有价值的,后续会推广。

Total Blocking Time[48] (TBT)

这是一种新的度量标准,有助于量化页面在变为可靠交互之前处于非交互状态的严重程度(也就是说,主线程至少在5s内没有运行超过50ms的任务(长任务))。度量的是从第一次绘画(FP)到交互时间(TTI)之间的时间长短(在这段时间内,主线程被阻塞足够长的时间而无法响应用户输入)。所以说,低的TBT是良好性能的体现。(感谢 Boris[49] Artem)

Cumulative Layout Shift[50](CLS)

该指标突出显示了用户访问网站时多久遇到一次意外的版式变化(重排)。它研究了不稳定因素及其对整体体验的影响。分数越低越好。

Speed Index[51]

度量页面内容可视化填充的速度,分数越低越好。速度指数分数是根据视觉填充的速度计算的,但它只是一个计算值。它对视口大小也很敏感,所以您需要定义一系列与您的目标用户是被相匹配的测试配置。请注意,随着LCP作为一种新度量标准的出现,它变得不那么重要了(谢谢,Boris, Artem!)。

CPU time spent

这是显示主线程被阻塞的频率和时间的度量指标,受到浏览器绘制、渲染、加载和执行JS等动作的影响。高CPU响应时间是不稳定体验的明显指标,也就是说,这时候用户会体验到他们的操作和响应之间存在明显的滞后。使用WebPagetest,您可以在“Chrome”选项卡上选择“Capture Dev Tools Timeline”[52],以显示在使用WebPagetest的任何设备上运行时,主线程的被阻塞的具体细节。

Component-Level CPU Costs[53]

类似上面的 CPU time spent,这个由Stoyan Stefanov提出的指标主要用于度量JavaScript对CPU的影响。这个指标的想法是使用每个组件的CPU指令计数来独立地了解每个组件中Javascript其对整体体验的影响。可以使用Puppeteer和Chrome来测量。

FrustrationIndex[54](沮丧指数)

上面介绍的许多指标解释了特定事件发生的时间,而Tim Vereecket提出的FrustrationIndex指标则着眼于各个里程碑之间的间隔,而不是独立地衡量它们。它衡量最终用户感知到的关键里程碑,例如 标题可见、第一个内容可见、视觉上准备就绪、页面准备就绪,并计算一个分数,指示加载页面时的沮丧程度。间隔时间越大,用户感到沮丧的可能性就越大。对于用户体验而言,这可能是一个很好的KPI。Tim发表了一篇FrustrationIndex介绍及其工作原理的详细帖子[55]

Ad Weight Impact[56]

如果您的站点依赖于广告产生的收入,那么跟踪与广告相关的代码大小是很有用的。Paddy Ganti写了1个脚本[57],可以构建了两个URL(一个正常,一个阻止广告),通过WebPagetest提示可以生成比较视频,并报告广告的增量。

Deviation metrics(偏差指标)

正如Wikipedia工程师指出的那样,结果中存在多少差异的数据可以侧面反映您测量仪器的可靠性,以及应该对偏差和异常值给予多大的关注。较大的差异表明测试仪器的设置中需要进行调整。它还有助于了解某些页面是否更难以可靠地衡量,例如 “由于第三方脚本会导致重大变化”。跟踪浏览器版本也是一个好主意,这样可以方便地了解新版本的浏览器对性能的提高。

Custom metrics[58]

自定义指标的定义来源于您的业务需求和客户体验。它要求您明确页面中重要的像素、关键脚本、必要的CSS和相关资源,并衡量它们对用户感知速度的影响。对于这一点,您可以监控Hero Rendering Times[59],或者使用Performance API[60],为对您的业务非常重要的事件标记特定的时间戳。此外,您还可以通过在测试结束时执行任意JavaScript来使用WebPagetest收集自定义指标。

请注意,“首次有效渲染时间(FMP)[61]”并未出现在上面。FMP用于深入了解服务器首次输出任何有意义数据的速度。较大的FMP通常反映JavaScript阻塞了主线程,也可能是后端/服务器出现了其他问题。但是,该度量标准最近已被弃用[62],因为在大约20%的情况下它似乎并不准确。Lighthouse也将在下一版本不再支持FMP[63] 仔细检查最新的以用户为中心的性能指标和建议[64],以确保您对页面性能时监测是可靠的。

Steve Souders对每个指标都进行了详细的解释[65]。需要注意的是,可交互时间(TTI)是通过在实验室环境中运行自动审核来测试的,而首次输入延迟(FID)这种需要实际的用户体验的指标,因此实际用户在体验时会明显感觉比测试中的慢。总体而言,始终测量和跟踪这两个参数应该是个不错的主意。

根据您的应用环境,首选指标可能会有所不同,举两个例子:对于Netflix TV UI,输入响应性,内存使用率和TTI更为关键,而对于Wikipedia而言,最先/最后的视觉变化时间点和CPU响应时间指标则更为重要。

注:FID和TTI都没有考虑用户滚动行为;滚动可以独立进行,因为它是非主线程的,所以对于许多内容消费站点来说,这些滚动相关指标可能不那么重要(谢谢Patrick提醒!)

network-requests-first-input-delay

以用户为中心的性能指标可以更好地反映实际的用户体验。首次输入延迟(FID)是一个新的度量标准,它试图实现这一点。

04 收集典型用户的设备上的数据

为了收集准确的数据,我们需要彻底全面地选择要测试的设备。在大多数公司中,这意味着需要调查分析并根据最常见的设备类型来创建用户画像。但是一般情况下,仅凭用户画像分析并不能提供完整的信息。因为有些用户可能因为他们的设备体验太慢或者显示不完美而离开网站,导致用户画像分析时忽略了这部分用户。因此,另外对目标客户群体中的通用设备进行研究可能是一个更好的主意。

根据国际数据公司(IDC)的数据显示,2018年至2019年期间,全球87%的移动电话都是Android设备[66]。消费者平均每两年升级一次手机[67],而在美国,手机更换周期为33个月[68]。全球最畅销手机的平均售价将低于200美元。

那么,一个有代表性的慢设备是:已经使用至少24个月的Android设备、价格在200美元或更低、运行在低速3G、400ms RTT和400kbps传输模式下,这只是稍微悲观预期的配置。当然,对于您的公司来说,这可能会非常不同,但这已经足够接近大多数客户了。事实上,针对您的目标市场调查一下当前的亚马逊畅销机型[69]可能是个不错的主意。(感谢Tim Kadlec,Henri Helvetica和Alex Russel的指点)

那么选择什么样的测试设备呢?按上面描述的样子,我们是在开放的设备实验室里,选择Moto G4/G5 Plus,三星中端设备(Galaxy A50,S8),不错的中档设备,如Nexus 5X,小米A3或小米Redmi Note 7,以及速度较慢的Alcatel 1X或Cubot X19,这是一个不错的组合。对于较慢的热门设备的测试,你也可以买一台Nexus4,价格只有100美元左右。

此外,检查每个设备使用的芯片组,机型组合不要过度集中在一个芯片组中: 建议包含几代的骁龙CPU(Snapdragon)和苹果CPU(Apple)以及低端的Rockchip、联发科(Mediatek)(谢谢Patrick提醒)

如果您手头没有设备,可以先在在台式机上模拟移动体验:节流的3G网络(例如300ms RTT、1.6 Mbps下行、0.8 Mbps上行)和CPU限速(减速5倍)上进行测试。最终切换到常规3G、低速4G(例如170ms RTT、9 Mbps下行、9 Mbps上行)和Wi-Fi。为了让性能影响更明显,你甚至可以参考facebook的做法在每个周二引入2G网络[70],或者在办公室设置一个节流的3G/4G网络[71],更方便地进行测试。

请记住,在移动设备上,我们应该预期会比台式机慢4到5倍[72]。移动设备有不同的GPU、CPU、内存和不同的电池。这就是为什么我们需要真机测试组合,并且始终在这些设备上进行测试[73]

tuesday-2g-opt

一周中最慢的一天。Facebook推出了2G的周二服务,让慢网速更容易被体验和可视化。

幸运的是,有许多很棒的选项可以帮助您自动收集数据,并根据这些指标衡量您的网站在一段时间内的表现。良好的性能图表应该含有一组性能指标,并且每个指标都有实验室数据和真机数据:

前者在开发期间特别有用,因为它能帮助您在开发产品时识别、拆分和修复性能问题。后者则对于长期维护非常有用,因为它将帮助您了解在用户实际访问站点时正在发生的性能瓶颈。

通过利用内置的RUM API(如导航时间[74],资源加载时间[75],渲染时间[76],长任务[77]等),综合测试工具和RUM可一起为您的Web应用程序提供完整的性能图。您可以使用PWMetrics[78],Calibre[79],SpeedCurve[80],mPulse[81]和Boomerang[82],Sitespeed.io[83],它们都是性能监控的绝佳选择 此外,使用Server Timing返回头[84],您甚至可以在页面中的某个点同时监控后端和前端的性能。

注:在浏览器外部使用网络调节器[85]总是比使用浏览器内置的更为可靠,例如,DevTools由于其实现方式的原因,在HTTP/2的push过程中,交互时长存在问题(感谢Yoav,Patrick反馈!)。对于Mac OS,我们可以使用Network Link Conditioner[86],Windows中可以使用Windows Traffic Shaper[87],Linux中可以使用netem[88]和FreeBSD的虚拟网络[89]

lighthouse-screenshot

Lighthouse是集成在DevTools中的一个性能审计工具

05 分别建立“干净”和“客户”配置文件用于测试

在监控工具中运行测试时,通常的策略是关闭杀毒软件和占用CPU的后台任务,清除后台带宽传输,使用干净的用户配置文件进行测试,并且不使用浏览器扩展,以避免出现不正确的结果(Firefox[90]、Chrome[91])。

此外,最好再研究一下客户经常使用的扩展,并使用专用的“客户”配置文件进行测试。实际上,某些扩展可能会对您的应用程序产生明显的性能影响[92](研究[93]),并且,如果您的用户经常使用它们,则可能需要先考虑一下。仅仅只用“干净”配置文件进行测试可能会导致结果过于乐观,而在用户实际体验的时候表现很糟。

06 与您的同事分享性能文化

确保团队的每个成员都熟悉性能文化,以免造成误解。每个决策-无论是设计,营销还是介于两者之间的任何决策-都会影响性能。在整个团队中分配责任和所有权将在以后简化以性能为中心的决策,根据性能预算和早期定义的优先级来权衡设计决策。

设定现实的目标

07 响应时间100ms,每秒60帧

为了让交互感觉流畅,页面响应用户的输入动作最好小于100ms。如果超过这个时间,用户就会觉得这个页面很迟钝。Rails是一个以用户为中心的性能模型,它为您提供了健康页面的目标:为了达到<100毫秒的响应时间,页面必须每隔<50毫秒将控制权交还给主线程。输入延迟估算[94]可以告诉我们是否达到该阈值,理想情况下,它应该低于50ms。对于像动画这样的敏感点,最好在你执行动画的时候什么都不做。

rail-perf-model-opt

RAIL[95], 一个以用户为中心的性能模型

另外,动画的每一帧都应在16毫秒内完成,从而达到每秒60帧(1秒÷60 = 16.6毫秒)- 最好在10毫秒以内。由于浏览器需要时间才能在屏幕上绘制新的帧,因此您的代码应在16.6毫秒之前完成执行。有关120fps的目标(例如iPad Pro的屏幕以120Hz运行),Surma提供了一些120fps的渲染性能解决方案[96],但这可能有点超前了,不是我们目前追求的目标。

对性能预期持悲观态度,对界面设计持乐观态度,合理利用浏览器空闲时间[97](关注idlize[98]和idle-until-urgent[99])。当然,上面说的这些目标适用于衡量运行时性能,而不是加载性能。

08 3G环境下 FID < 100ms, TTI < 5s, Speed Index < 3s, 关键文件大小 < 170KB (gzip压缩后)

虽上述指标可能很难实现,但一个好的最终目标是速度指数(Speed Index)[100]低于3s,可互动时间(TTI)低于5s[101],对于二次访问,TTI目标是低于2s(一般需要利用Service Works的离线缓存才能实现)。最大内容绘制时间(LCP)的目标是1s以下,需要最大限度地减少总阻塞时间和累计布局的变动。可接受的首次输入延迟(在LightHouse中是最大的潜在首次输入延迟)要低于130-100ms。如上所述,我们正在考虑的基准是200美元的Android手机(例如Moto G4),在低速3G网络上,以400ms RTT和400kbps的网络配置进行模拟测试。

通过网络中快速展示页面,有有两个主要限制因素。一方面,由于TCP慢启动[102],我们受到网络传递限制: HTML的前14KB(10个TCP数据包,每个1460字节,大约14.25 KB,可以大概这样估计[103])是最关键的有效传输块,并且是内容中唯一可以在第一次网络往返就传输完成的部分( 加上移动网络唤醒时间的原因,这就是您在RTT为400ms网络的环境下在1s内能获得的最多内容)。

(注:由于TCP通常无法充分利用网络连接,因此Google开发了TCP瓶颈带宽和RRT(BBR)[104],这是一种较新的为现代网络设计的TCP延迟控制和TCP流控制的算法[105]。在慢网络能够根据实际情况阻塞请求,而不是像TCP那样造成数据包丢失,它明显更快[106],具有更高的吞吐量和更低的延迟-算法的工作方式也不尽相同[107]。尽早确定静态资源的优先级仍然很重要,但14 KB可能与BBR无关 (谢谢Victor, Barry!)

另一方面,由于JavaScript解析需要时间,我们在内存和CPU方面存在硬件限制(将在后面详细讨论)。为了实现上面所述的目标,我们必须考虑JavaScript关键文件的大小预算。关于该预算应该是多少(这在很大程度上取决于您的项目的性质)有不同的看法,但是压缩到170KB JavaScript的文件已经需要花费了1s才能在普通手机上进行解析和编译。假设170KB的文件在解压缩时扩展到原来的3倍(0.7MB),那在Moto G4 / G5 Plus上这类机型上就已经很大达到“体面的”用户体验了。

如果你想瞄准东南亚、非洲或印度等增长中的市场,你必须考虑一组非常不同的限制因素。Addy Osmani介绍了主要的手机限制[108],例如几乎没有低成本、高质量的设备、无法获得高质量的网络和较贵的流量费用,以及针对环境的PRPL-30性能预算和开发指南。

12-30kb-front-end-performance-checklist-2020

根据Addy Osmani所述[109],对于延迟加载的路由中的JS,建议的大小应 <35 KB

13-prpl-budget-front-end-performance-checklist-2020

Addy Osmani建议,如果目标是智能手机,就采用PRPL-30性能预算(30KB gzipped+压缩后的初始化JS包)

事实上,谷歌的Alex Russel建议以130~170KB(gzipped后)作为一个合理的包大小上限。然而在现实世界中,大多数产品甚至都超过很多:现在JS包的中值大小约为417KB,与2015年初相比增长了42%。在中等收入人群的移动设备上,这将带来15~25秒的可交互时间(TTI)。

11-perf-phones-front-end-performance-checklist-2020

2019年全球销量最高智能手机的Geekbench CPU性能基准。JavaScript是强调单核性能(请记住,与Web平台的其余部分相比,它本质上更像是单线程的),并且受CPU的限制。摘自Addy的文章《在20美元的功能手机上快速加载网页》[110]

当然,JS包大小的最大值限制不是绝对的,我们可以超出上面说的JS包大小预算。我们可以根据浏览器主线程的活动(例如:开始渲染之前的绘制时间)设置性能预算,或者跟踪前端对CPU的占用量[111]。Calibre[112]、SpeedCurve[113]和Bundlesize[114]等工具可以帮助您控制预算,并且可以集成到您的构建流程中。

最后,性能预算可能不应该是一个固定值。根据网络连接的不同,性能预算应该有所调整[115]。但是要记住,在慢网速下,无论如何使用,每个包大小都非常“昂贵”(占用宝贵的带宽)。

注:随着HTTP/2的广泛应用、即将到来的5G、快速发展的手机硬件和蓬勃发展的SPA的时代,设定如此僵化的预算听起来可能有些奇怪。然而,考虑我们面对的网络和硬件的不可预测性质时,这些性能预算限制听起来又确实是合理的,包括从拥堵的网络到缓慢发展的基础设施,到数据上限、代理浏览器、省流量模式和复杂的漫游费用。

file-size-budget-fast-default-addy-osmani-opt

来自Addy Osmani的《默认快速:现代加载最佳实践》[116](幻灯片19页)

perf-budgets-network-connection

性能预算应根据一般的移动设备的网络条件进行调整(图片来源:Katie Hempenius)

定义环境

09 选择并设置构建工具

不要过于关注那些被认为很酷的工具[117]。坚持在您的开发流程中进行构建优化,无论是Grunt、Gulp、Webpack、Parcel还是这些工具的组合。只要获得了想要的结果,并且维护构建过程没有问题,那就足够了。

在众多构建工具中,Rollup对开发者的吸引力越来越大,但Webpack似乎是最成熟的一个,它提供了数百个插件来优化构建的大小。尽管刚开始使用Webpack是很困难的。如但果你想掌握它,这里有一些很棒的资源:

Webpack文档[118] - 显然这是一个很好的起点,Raja Rao编写的Webpack代码混淆[119]和Andrew Welch编写的Webpack配置注释都是了解webpack一个很好的起点

Sean Larkin发布了1个关于Webpack的免费课程: webpack核心概念[120]。Jeffrey Way也发布了一个关于Webpack的非常棒的免费课程:所有人都必须了解的webpack[121]。这两个对每个想深入研究Webpack的开发者都很友好

webpack基础知识[122]是1个非常全面的4小时课程,由Sean Larkin在FrontendMasters上发布

如果您对Webpack已经比较熟悉了,那么可以试试阅读Rowan Oulton发布的使用Webpack改善建筑性能的现场指南[123],和BenediktRötsch进行的有关将Webpack捆绑压缩的研究[124]

Webpack示例[125]有着数百个现成的Webpack配置,并按照主题和用途分类。另外:还有一个Webpack配置生成器[126],可以生成一个通用的配置文件

awesome-webpack[127]是优秀的Webpack资源,库和工具的集合,有文章,视频,课程,书籍和示例等,包括在Angular,React中的最佳实践,当然也包括和框架无关的webpack资源

10 默认使用渐进式增强

尽管这个概念已经提出了这么多年,将渐进式增强[128]作为基础原则来指导前端体系结构和部署仍然是一个不错的选择。首先设计和构建基础和核心体验,然后使用强大的浏览器高级特性来增强界面,从而获得弹性式[129]的用户体验。如果你的网站在低性能设备、网速慢、屏幕不好的环境下都能流畅地运行,那么在速度快的机器上它就会运行更快表现更佳。

实际上,通过自适应服务模块[130],我们可以同时为低端设备提供“精简”的核心体验,而为高端设备提供更复杂的功能。渐进式增强这种模式短期内应该不会消失。

11 选择一个良好的性能基准

由于有非常多的未知因素影响加载性能-网络、负载均衡、缓存覆盖、第三方脚本、解析器阻塞模式、磁盘I/O、IPC延迟、安装的扩展、防病毒软件和防火墙、后台CPU任务、硬件和内存限制、二级/三级缓存的差异、RTTS -- 因此JavaScript的体验成本非常高[131],仅次于默认情况下阻止页面呈现的Web字体和经常消耗太多内存的图像。随着性能瓶颈从服务器转移到客户端[132],作为开发人员,我们必须更详细地考虑所有这些未知因素。

上面提到的170KB的预算已经包含关键路径HTML/CSS/JavaScript、路由器、状态管理、实用程序、框架和应用程序逻辑,所以我们必须彻底检查我们选择的框架的网络传输成本、解析/编译时间和运行时成本[133]。幸运的是在过去的几年里,浏览器在解析和编译脚本的速度方面有了巨大的进步[134]。然而,JavaScript的执行仍然是主要的性能瓶颈,因此我们必须密切关注脚本执行时间和网络传输可能会产生的任何影响。

正如Seb Markbège所指出[135]的,衡量框架启动成本的一个好方法是先渲染试图,然后删除视图再二次渲染,这样就可以知道框架绘制的成本。因此首次渲染视图之前往往需要预热一堆延迟编译的代码,更大DOM树在绘制时受益更多。二次渲染则是模拟页面上的代码复用度是如何随着页面复杂度的增加而影响性能特征。

12 评估框架和依赖关系

现在,不是每个web应用都需要前端框架[136],在单页应用程序也不是每个页面都需要加载框架。在Netflix的场景中,“从客户端删除React,一些第三方库和相应的应用程序代码可以将JavaScript的总量减少200KB以上,从而使Netflix首页登录的可互动时间减少了50%以上[137]。” 然后,该团队利用用户在登录页面上花费的时间来预取React,这样做在用户可能访问的后续页面中就不用继续加载React了(有关详细信息,请继续阅读[138])。

可能大家都知道,但还是值得一提:确实有一些项目可以从完全删除现有框架中受益[139]。选择框架后,您将至少使用几年,因此,如果需要使用框架,请确保您的选择是明智的[140],并经过深思熟虑[141]

Inian Parameshwaran评估了最流行的前50个框架的性能[142](用First Contentful Paint[143]评估,即从导航到浏览器首次渲染DOM内容的时间)。Inian发现,Vue和Preact是总体来说最快的框架-在台式机和移动设备上都是如此,其次是React(幻灯片[144])。可以检查候选框架和建议的体系结构,并研究其中大多数解决方案的性能,例如使用服务器端渲染或客户端渲染,或者结合两者。

基准性能成本很重要。根据Ankur Sethi的研究[145],“在印度,无论你如何优化,React应用程序在普通手机上的加载速度永远不会比1.1s快,Angular应用程序总是需要2.7s才能完成启动,Vue应用程序的用户则需要等待1s才能开始使用它。” 当然,您可能并没有将印度作为您的主要市场,但是使用次优网络条件访问您的web网站的用户将拥有类似的体验。使用框架可能会降低用户体验,但您的团队也获得了可维护性和开发人员效率。因此使用框架需要经过深思熟虑。

您可以在Sacha Greif的12分制评分系统[146]上评估一个框架(或任何JavaScript库)包括:探索特性、可访问性、稳定性、性能、包生态系统、社区、学习曲线、文档、工具、跟踪记录、团队、兼容性、安全性等。考虑到整体耗时较大,在选择选项之前至少考虑总的大小成本+初始解析时间是个好主意;Preact[147]、Inferno[148]、Vue[149]、Svelte[150]或Polmer[151]等轻量级框架可以很好地完成工作。基线的大小将定义应用程序代码的约束。

有许多工具可以帮助您就依赖项和可行替代方案的影响做出明智的决策:

一个好的开端是为您的web应用程序选择一个好的默认种子工程。Gatsby[158](React),Vuepress[159](Vue),Preact CLI[160]和PWA Starter Kit[161]针对不同框架提供了合理的默认种子,可以在普通移动开发中快速开箱即用。另外,请查看web.dev特定于针对React和Angular框架的性能指南[162],该指南应该在今年晚些时候进行扩展(感谢Phillip!)。

09-high-sell-phones-front-end-performance-checklist-2020

畅销手机的CPU和计算性能(图片来源:Addy Osmani)

13 考虑使用PRPL模式和App Shell架构

不同的框架对性能有不同的影响,需要不同的优化策略,因此您必须清楚地了解您将依赖的框架的所有细节。在构建Web应用程序时,建议研究PRPL模式[163]和App Shell架构[164]。这个理由非常简单:只推送使页面初始化并可交互所需要的最小代码(Push),以便快速呈现初始路由页面(Render),然后使用Service Worker来缓存和预缓存后续资源(Pre-Caching),再以异步方式延迟加载所需的路由资源(Lazy-Load)。

app-build-components-dibweb-c-scalew-879-opt

PRPL代表推送关键资源(Pushing critical resource),渲染初始路由(Rendering initial route),预缓存剩余路由(Pre-caching remaining routes)和按需延迟加载剩余路由(Lazy-loading remaining routes on demand)

appshell-1-o0t8qd-c-scalew-799-opt

App Shell是支持展示用户界面的最小HTML、CSS和JavaScript

14 是否对API的性能进行了优化?

API是指应用程序通过所谓的socket向内部和第三方应用程序交换数据的通信通道。在设计和开发API时[165],我们需要一个合理的协议来实现服务器与第三方请求之间的通信。Restful API[166](REST[167])是一种广泛验证有效的选择:它定义了一组约束,开发人员可以遵循这些约束以使内容以高性能,可靠和可伸缩的方式进行访问。符合REST约束定义的Web服务称为RESTful Web服务。

与普通的HTTP请求一样,当从API检索数据时,服务器响应中的任何延迟都将传播到最终用户,从而影响渲染。当资源想要从API检索某些数据时,它将需要从相应的端点请求数据。渲染来自多个资源的数据的组件,例如在每个评论中包含评论和作者照片的文章,可能需要多次往返到服务器来获取所有数据,然后才能渲染。此外,通过REST返回的数据量通常超过渲染该组件所需的数据量。

如果许多资源都需要来自某个API的数据,则该API可能会成为性能瓶颈。GraphQL[168]为这些问题提供了高性能的解决方案。本身,GraphQL是API的一种查询语言,并且是服务器端运行时的,用于通过使用为数据定义的类型系统执行查询。与REST不同,GraphQL可以在单个请求中检索所有数据,并且只响应所需的内容,而不会像REST通常那样过度或不足地获取数据。

此外,因为GraphQL使用模式(schema,定义数据结构的元数据),所以它可以提前将数据组织成所需的结构,因此使用GraphQL,我们可以删除用于处理状态和数据结果的JavaScript代码[169],从而产生在客户端上运行更快更干净的应用程序代码。

如果您想开始使用GraphQL,Eric Baer在Smashing Magazine上发表了两篇精彩的文章:GraphQL入门:为什么我们需要一种新型API[170]和GraphQL入门:API设计的发展[171](感谢Leonardo提醒!)。

redux-rest-apollo-graphql

REST和GraphQL之间的区别: 通过左侧的Redux+REST的模拟对话和右侧的Apollo+GraphQL的模拟对话来说明(图片来源:Hacker Noon)

15 使用AMP还是Instant Articles?

根据您团队的优先级和战略,您可能需要考虑使用Google的AMP[172]或Facebook的Instant Articles[173]或Apple的Apple News[174]。没有它们您也可以实现良好的性能,但是AMP确实提供了具有免费内容交付网络(CDN)的可靠性能框架,而Instant Articles可以提高您在Facebook上的可见性和性能。

这些技术为用户带来的明显好处是:基本可以保证性能,因此有时他们甚至更喜欢AMP/Apple News/Instant Pages的链接,而不是“常规”、可能比较臃肿的页面。对于处理大量第三方内容的内容繁重的网站,这些技术可能会明显地降低渲染耗时。

这些并不是没用[175]。例如,根据Tim Kadlec的说法:“AMP文档往往比它们的同行更快,但这并不一定意味着这个页面性能更好。从性能的角度来看,AMP并没有太大的不用”。

对网站所有者来说,好处是显而易见的:这些格式在他们各自的平台上都更容易被曝光,并能在搜索引擎中提升排名[176]。您也可以通过AMP作为PWA的数据源,来构建渐进式Web AMP[177]。不利的一面是什么?显然,AMP这类技术类似围墙的花园,使得开发人员需要开发和维护针对它们的单独版本,例如Apple的Instant Articles没有实际的URL[178],我们在代码中就要单独处理这种情况(感谢Addy,Jeremy!)。

16 合理选择CDN

根据您拥有多少动态数据,您可以将内容的某些部分“外包”给静态站点生成器[179],将其推送到CDN并从中提供静态版本,从而避免数据库请求。您甚至可以选择基于CDN的静态托管平台[180],使用交互式组件作为增强功能丰富您的页面(JAMStack[181])。事实上,其中一些生成器(比如React生态的Gatsby[182])实际上就是个网站编译器[183],它提供了许多开箱即用的自动化优化。随着编译器不断地为编译添加优化,编译后的输出会越来越小,越来越快。

请注意,CDN也可以提供动态内容。因此,不必将CDN的应用限制在静态资源。仔细检查您的CDN是否支持执行压缩和转换(例如,在格式方面进行图像优化,压缩和调整大小),对servers worker的支持[184],页面片段缓存,将它们在CDN层面组合页面的静态和动态部分(距离用户最近的服务器)和其他支持的特性。此外,请检查您的CDN是否也支持HTTP over QUIC(HTTP/3)[185]

注意:根据Patrick Meenan和Andy Davies的研究,设置HTTP/2优先在许多CDN上实际上是无效的[186],因此在选择CDN时要小心。帕特里克(Patrick)在他最近的HTTP/2优先[187]演讲中有更多细节(感谢Barry!)。

关于本文

译者:@陈隆德 译文:https://mp.weixin.qq.com/s/d9J-_aF9K8QTUtemol-EfQ 原文:https://www.smashingmagazine.com/2020/01/front-end-performance-checklist-2020-pdf-pages

为你推荐


【第1907期】前端性能优化实践 之 百度App个人主页优化


【第1700期】体验,不只是用户的!Ant Design 在蚂蚁中台的应用


【第1875期】如何在页面极速渲染3D模型


在公众号后台回复关键词 2020前端性能优化清单 获取史上最长参考资料