阅读 510

[译]网络性能入门:2019年初学者指南

原文地址:Getting started with web performance: 2019 beginner’s guide
原文作者:Jakub Gieryluk
译文出自:FE-star/speed
译者:smallbonelu
校对者:[]
本文链接:[]

有很多非常好的文章介绍了关于如何使用新功能X或技术Y亦或工具Z来提高网站性能。如果你对该主题不熟悉,那么浏览现代网络性能的迷宫可能会很困难。在本文中,我将尝试提供一个指南,以开始你的性能之旅。

了解你的用户

在开始之前,最好知道你的用户是谁以及他们如何使用你的网站,以便以后做出明智的决定。从性能方面来看,重要的事情是:

  • 移动与桌面浏览器的用户的比例,
  • 通过浏览器引擎来划分用户:类似Chrome,Safari,Firefox,Edge,IE,
  • 按国家划分用户。

你很可能已经使用了可以回答这些问题的分析工具。花一些时间来分析这些数据并将其写下来,包括分析日期,以便在需要时轻松访问,并在几个月内进行重新评估和比较。

请注意,全局统计信息通常与本地统计信息不同:特别是在数据成本较高的国家/地区,UC浏览器,Opera Mini等浏览器非常受欢迎,而其他地方几乎未使用过。

要了解用户的真实浏览体验,以及你的网站与竞争对手的比较情况,你可能需要查看Chrome UX报告

确定测试URL

提出一些URL,这些URL将成为性能分析和优化的候选者代表。你可能希望某些URL's能够获得大量流量,随着时间的推移拥有相对稳定的内容,并且可以很好地覆盖你的网站的各种功能

你的首页是自然的第一候选者。对于博客或新闻网站,过去流行的文章将是另一个候选者。

例如,Wikimedia的性能团队使用英语维基百科的“Barack Obama”和“Sweden”文章进行基准测试和性能监控。

了解这些工具

在几个性能工具中运行你的页面,以熟悉它们并确定一些“速效方案”。不同的工具可能提供其他工具缺失的见解,或者可能比其他工具解释得更好 - 所以值得试一试所有的这些工具,看看哪些对你的特定用例最有用。

  • Lighthouse可能是最容易上手的工具,它提供了大量有关重度依赖JS的现代Web应用程序的详细信息:可以通过在Chrome浏览器开发工具的“Audit"选项卡中来运行,或者从任何浏览器本地运行web应用程序WPT
  • WebPageTest 是网络性能的“瑞士军刀”,非常强大,并为高级用户提供了许多“隐藏功能”。你进入webperf的次数越多,你使用它的次数也就会越多。电影胶片和视频比较视图是它的一些杀手级功能。Using WebPageTest一书是一个很好的参考。
  • Yellow Lab Tools 还可以提供各种性能指标的有用细分。
  • 虽然不是严格关注性能,但是也可以通过WebHintRedBot查看一下,它们可以发现你网站的互操作性和正确性问题,提出改进建议,并帮助你摆脱无用的HTTP头。
  • 另请参阅SiteSpeed.io以获取大量开源webperf工具。
  • 除此之外,还有许多商业性能监控服务,其中一些还提供有限的免费工具。

在这一点上,你已经知道一些相对容易修复的问题(至少在理论上),但影响很大:比如未压缩资源,未优化图片等。

了解你网站的HTML

获取你网站的HTML输出(也就是页面源码)(例如在Firefox和Chrome中使用快捷键Ctrl-U),重新格式化并进行分析。创建一个关于哪些标签组成了你的HTML的高级文档,为什么会使用这些标签(如果你不知道,请询问你的同事),以及占用了多少字节。

在长期维护的项目中,多年来积累的一些标签可能已经不再需要,那么就可以安全地移除它们。(如果它是第三方JavaScript库,那就附加奖励了!)

了解你网站的子资源

接下来的事情是明白你的网站,了解一个页面的加载触发了哪些HTTP请求,何时触发以及为什么会触发。运行WebPageTest测试,将所有请求的列表(在底部)复制到电子表格,并分析每个请求的角色(特别是列表中的前10-20个),以及它们的重要程度可能会有所帮助。使用图表软件创建流程图可能对更好地理解它们之间的依赖关系关系也很有用。

如果你不确定给定请求的作用,你也许可以尝试阻止请求或人为的引入较大的延迟并查看网站的行为(这对于发现意外的单点故障依赖关系也很有用)。这有无数种方法可以做到:Chrome开发工具的*“Request blocking”功能,Fiddler 的“AutoResponder”(具有延迟)功能,以及WebPageTest的“Block”“SPOF”*功能; 即使是任意浏览器中的广告拦截器都可以实现。

通过了解哪些请求对用户体验至关重要,哪些请求是次要的,你可以更好地确定优化工作的优先级。如果可能,请异步加载你的脚本使用defer

RequestMap是一个可用于 审核来自你的webapp的第三方请求的工具,并可帮助你发现通常不利于网站性能的长链请求。

隔离功能的方法

复杂的Web应用程序通常必须实现许多功能并触发许多请求; 同时分析所有这些并不总是那么容易。通过能够轻易禁用的某些功能(例如通过查询字符串),你可以让你的生活更美好。

小范围地测试

面向性能的浏览器功能通常是非常新的,因此尚未经过实战测试,这些功能可能在不同的浏览器中存在一些难以察觉的错误或实现的行为略有不同。 当你将新浏览器功能直接应用于现实中的大型项目时,了解新浏览器功能的确切工作原理也可能会非常棘手。

一个好主意可能是回到基础部分,创建小的隔离HTML页面进行测试,将它们部署到公共服务器(我使用GitHub Pages),并在所有主流浏览器中运行WebPageTest测试。

由于统一的WebPageTest UI,所以可以轻松地比较浏览器引擎的行为 - 比查看不同的开发工具界面要容易得多。如果你发现了一些意外行为,那么你已经有一个简化版的测试用例可以用来向浏览器厂商提交错误报告。

想一想要测量什么

大多数早期优化(如删除/压缩assets)都可以安全地执行,并且会立即带来明显的改进,通常不会导致回退。但是为了更进一步和基于长期发展的考虑,你需要确切地知道你的KPI是什么以及如何衡量它们

这可能非常难以定义,它在很大程度上取决于你拥有的网站/网络应用程序类型。浏览器触发loadDOMContentLoaded事件的时间等“传统”指标并不适合现代网站,更不用说重度依赖JS的SPA了(单页面应用程序)。在任何情况下,请忘掉“one number to rule them all”。你很可能需要多个指标来了解全貌。

了解现有的性能指标

除了难以定义之外,某些事情仍难以准确测量,特别是视觉事件(“我的图片和文字何时变得可见?”)。这很难回答,因为文本呈现可能取决于外部CSS和webfonts的可用性(如果它们正在等待下载,这可能导致所谓的不可见文本闪烁),而图片的load事件的触发也不能精准的知晓了(与在屏幕上实际渲染像素的时间相比)。

直到最近,浏览器根本没有提供足够的细节来衡量渲染性能,而WebPageTest的Speed IndexVisually Complete也就成为了金律。这些是非常复杂的指标,是通过获取一系列屏幕截图并分析渲染内容随时间变化的方式创建的,但你应该花一些时间来理解它们 ; 它们比简单的指标更好地传达用户体验。

话虽如此,浏览器(特别是Chrome)在2018年在这个领域取得了一些进展,它发布了像PerformanceObserver这样的浏览器内置APIs,这个APIs提供了诸如First Contentful PaintFirst Meaningful Paint等事件。如果你对细节感兴趣,请查看Paul Irish的演讲

创建自定义指标

除了现成的指标外,你可能还需要一些于你网站的特定的自定义指标; 也许是将你的JavaScript代码中自定义事件的时间戳与资源的获取时间和大小相结合,这些信息可以从Resource Timing API来获取。

在创建自定义指标时,你可能需要混合使用定义明确,细粒度,可操作的指标(例如,“JavaScript method1()和method2()调用之间的时间”以及可以传达真实用户体验的更高级别指标(例如“从HTML的responseStart到一个myImportantAppLifecycleEvent“的时间)。前者是明确致力于改进给定指标(以及捕捉意外回退)的良好基准。后者不太容易随着大型重构和代码更改而变化,这些更改会改善一个细粒度指标而代价就是会恶化另一个。

请注意,Navigation TimingResource Timing APIs在某些早期实现中存在错误; 注意异常值(负值或极大值)可能会扭曲统计数据。最后,你可能会使用像boomerang这样的库,而不是自己编写。

熟悉统计基础知识

为了能够理解真实用户监控(RUM)数据,你需要了解平均值和中位数之间的差异,以及什么是百分位数

某些类型的优化可能在中位数中不可见,但可能在第90,95和99百分位数上有很大差异。一般来说,你应该避免使用平均值,因为它们可能会产生误导,并且强烈建议考虑使用提供百分位数据和分布式分布图的工具。

请记住,独立事件是独立的 ; 你不能只对平均值或百分位数求和,并假设获得的数据具有代表性或意义。

注意分析

正如本文开头所提到的,分析全局数据集可能会产生误导。例如,你网站上的某些功能可能仅供登录用户使用。这可能意味着登录页面和未登录用户的登录页面的性能前景可能会有很大差异。

确定影响性能的主要标准,并能够缩小分析视图范围以便在多种变体(登录/未登录,移动/桌面等)之间进行比较

学会使用限制

在功能强大的MacBook Pro上进行本地测试,使用光纤 + 千兆WiFi时,无论如何,你的页面都会感觉很快。但这并不是你的用户在一个中端的Android设备上使用移动网络的情况,他们也许在通勤的时候(因此网络不稳定)访问你的网页。

这就是在测试页面时使用网络和CPU限制很重要的原因。(平心而论,这可能是一次令人震惊的体验。)

你可以在你喜欢的浏览器(Chrome示例)中,在操作系统级别(可能使用像Fiddler这样的代理)通过devtools启用限制,或者在使用WebPageTest(“高级设置”面板)运行测试时启用限制。网络限制在基准测试中也很有用,可以随时间推移获得可比较的数据。

如果你想更进一步了解,你可以尝试2G Tuesday的变化,或在你的办公室设置一个模拟慢速3G移动连接的测试WiFi。

区分延迟,带宽和CPU

随着新一代移动网络的安装和升级,互联网带宽每年都在迅速提高,即使在发展中国家也是如此。现代4G连接可能比过时的固定电话更好 - 连接类型可能是一个误导因素。

另一方面,由于物理限制,延迟不会快速改善。距离你的服务器数千公里的用户的长尾,不能做任何事情来改善他们的延迟,但通过确认问题并采取行动(最小化往返次数,识别TCP慢启动,通过dns-prefetch/ preconnect/ preload等,预先启动DNS / TCP / TLS /资源请求)可以显著缓解此问题。

最后但并非最不重要的是,虽然高端移动设备与昔日的台式机一样强大,但低端设备几乎没有改进 - 它们只是变得更便宜了,但仍然使用较慢的CPU和较小的内存(尽管在相同的网络条件下)。

特别是当涉及到大的JavaScript bundles时,带宽(下载)不再是瓶颈 - CPU速度(解析和执行)才是。

了解HTTP / 1.1和HTTP / 2之间的区别

HTTP / 2(简称h2,这令HTML编写者很困惑!)是HTTP协议的一个主要修订版,它显著改变了资源通过线路传输的方式,并且与HTTP / 1.1具有完全不同的性能特征。HTTP / 1世界的一些“最佳实践”(如域分片)在HTTP / 2中不再有意义,但同样重要的是,在各种浏览器和服务器中,某些HTTP / 2功能的实现是完全不同的,并且通常是不完整的

首先,在你最喜欢的devtools网络面板,检查你的assets是通过HTTP / 1还是HTTP / 2提供(右键单击列列表并勾选Protocol条目以使其显示)。

如果你的应用程序使用多个域来存储图片,脚本和动态数据,那么你很可能会混合使用这两者。一旦了解了这一点,请调整每个传输的最佳实践。通常,你应该尝试尽可能多地重用HTTP / 2连接 ; 浏览器会尝试通过将某些请求“合并”到同一个连接中,每个浏览器的实现会略有不同

(请记住,大多数开发者代理 - 比如Fiddler - 默认将所有连接降级到HTTP / 1.1。确保在进行性能调查时禁用它们,以避免观察到误导行为。)

通常,从2018年末开始,WebPageTest提供了比浏览器的devtools更高级的HTTP / 2信息,因此如果你对某些assets使用HTTP / 2,则应该花时间探索WPT瀑布流和连接视图。

成为瀑布流视图的朋友

WebPageTest是一个非常强大的工具,你可以从其瀑布流和连接视图中读取大量信息。这是一个完整的单独博客文章的主题,但简单来说,下面是你开始最能操作的信息:

  • 瀑布流的形状(越“垂直”越好),
  • “网络静默”的缝隙,
  • 关键资源的DNS,TCP,TLS的请求延时--- preconnectdns-prefetch是直接候选解决方案

了解瀑布流对于进行非凡的优化至关重要。你可以从这个关于瀑布流反模式的演示开始,然后通过自由探索逐渐深入探讨这个主题。

保持JavaScript不受影响

向客户端发送大量JavaScript代码是现代Web最重要的问题之一。 评估JavaScript非常昂贵 - 远远超过渲染大小相当的图像。当你遇到一个大型的现有项目时,要做很多的性能优化并不总是那么容易。话虽如此,这里有一些小技巧:

  • 使用Chrome开发工具中的coverage选项卡查找未使用的JavaScript和CSS。
  • 查看你使用的库并寻找更小的替代品。Bundlephobia非常适合用来进行npm artifacts比较。
  • 确保不要导入大型库而是只使用它提供的一些小功能。实际上,你可能根本不需要某些库; 现代JavaScript非常强大,而且polyfilling的选择比以往更容易
  • 更新依赖关系也可能会减少你的包大小(或者恰恰相反 - 请小心),有时是间接的 - 通过避免项目中重复的传递子依赖关系。

了解你的构建工具

像webpack这样的打包工具有很多配置选项可以帮助提高性能。阅读文档并完善配置可能需要一段时间,但这是一项很好的投资,可能带来很高的回报。特别是,code splitting是一种关键技术,可以最大限度地减少初始JavaScript有效负载并在加载时保持页面响应。

如果你正在使用babel来转换ES2015 +代码,请确保根据你的浏览器支持级别使用并正确配置babel-preset-env,以避免在最终打包中进行不必要的转换和polyfill。

归功于打包工具的tree-shaking(死代码消除)功能,将依赖项更新到较新的基于ES2015 +的版本可以使你的包更小。

考虑长期缓存

HTTP / 1世界的“常识”是将给定页面上所需的所有JavaScript合并为单个文件。如果你只进行一次页面部署并且永远不会再更改它了,这是合理的。但是,如果你定期更新部署,并且某些模块的更改频率高于其他模块,则将它们拆分为单独的包可能更有用,即使它们总是一起使用也是如此。

当使用HTTP / 2并且保持合理的打包数量时,多次下载的首次微小的延迟对于回访者增加的缓存命中率(因此避免昂贵的网络请求)来说,支付的代价很小。

获得正确的长期缓存需要可以进行重复构建,对旧版本的webpack来说很难,甚至是webpack 4。刚刚发布的(alpha版)webpack 5承诺将开箱即用的长期缓存作为核心功能,这是一个非常好的消息。

使用开发人员版本的Web浏览器

现在的Firefox(Beta / Dev Edition / Nightly),Chrome(Beta / Dev / Canary),Safari(技术预览版)的预发行版本非常稳定。他们在部署到最终用户之前提供新的Web平台功能和重要更改的预览,还提供了有关弃用功能的早期警告,并且在添加到主流版本数周/月之前通常会在在开发工具中提供显着的改进

懂得权衡利弊

改进一个指标有时意味着另一个指标的恶化; 在浏览器X中改进的可能在浏览器Y中产生回退。

提前考虑,定期测试所有主要的浏览器引擎,并确保保持平衡。在分析工具中创建视图或过滤器,以便能够快速隔离来自不同浏览器,不同国家/地区的统计信息等。部署重大更改时,请务必分别检查每个视图。

信任但要验证

警惕提供银弹,却不提及任何缺点的博客文章。始终测试多种浏览器和设备类型。

例如,<link rel=preload>如果使用得当并且符合你的需求的话,它是一个很好的功能,但是如果使用不当,它实际上可能会过度优先处理某些请求导致性能下降,从而牺牲了更重要的请求。

另一个例子:<script type="module">/ <script nomodule>是一种很有前途的模式,用于将现代JavaScript传输到现代浏览器并将ES5转换为传统的JS,但它会在某些浏览器中产生重复请求

请记住,一种方法不能解决所有问题

对高带宽网络用户有利的事情 - 例如预加载(prefetching) - 对于数据套餐有限或带宽有限的用户(发展中国家,数据漫游用户)并不总是有利。网络信息API,客户端提示,通过service worker重写动态请求可能有助于缓解这些问题。

性能是一个动态的目标

你的网站不是孤立的。浏览器会更新并且速度更快(但有时更慢),用户会更换他们的设备,移动和固定电话网络也会升级 - 在分析长期性能KPI时请记住这一点。

你的网站的受众特征也会随着在新的国家/地区受到欢迎而发生变化,在极端情况下,当你实现真正的大规模改进时,你的全局指标可能会更糟!

记录你学到的东西

快速学习太多东西时很容易迷失。记录你发现的新东西,为有用的URL等添加书签,以便以后回顾。在issue tracker中打开tickets以进一步研究一些想法也可能起到一些作用。

联系社区

perf社区并不大,但如果你遇到困难,你可以在WebPageTest论坛上依靠那些热心人士提供的帮助。Twitter也可能是一个很好的信息来源。

持续学习并保持输出,一次一件事

理解Web性能的复杂性需要时间,即使具备了所有知识,找到正确的执行方案有可能很困难。有时你只需要撸起袖子加油干,然后反复试验和试错。

目前还没有人发现性能银弹。学习新事物,提出想法,尝试,测量,权衡利弊,部署改进 --- 一次一个。

享受你(网站)的性能之旅!

附加资源

感谢Hine Courtenay为本文的草稿版本提供了大量修正,以及Doug Sillars提供的有用技巧。

关注下面的标签,发现更多相似文章
评论