提纲:Web 性能优化没有银弹。简单的静态网页得益于使用极少 JavaScript 代码的服务端渲染。库的谨慎使用能够为复杂的页面带来巨大的价值。javascript
Netflix 是最受欢迎的视频流服务之一。自 2016 年在全球推出以来,公司发现许多新用户不只经过移动设备完成注册,并且还使用了不太理想的网络链接。php
经过改进用于 Netflix.com 注册过程 JavaScript 代码和使用预加载技术,开发人员团队能够为移动和桌面用户提供更好的用户体验,并提供多项改进。前端
Netflix 开发者优化性能的地方是未登陆主页,用户在此页面注册并登陆站点。java
新用户和已登出用户的 Netflix.com 主页react
此页面初始包含 300KB 的 JavaScript 代码,其中一些是 React 和其余客户端代码(例如像 Lodash 的工具库),并且还有一些是必要的上下文数据用来给 React 的状态注水(hydrate)。android
全部 Netflix 的网页都由服务端 React 渲染,这些页面为生成的 HTML 和客户端应用提供服务,所以维持新优化的主页结构不变和保持开发人员体验的一致性一样重要。ios
Homepage 选项卡是最初使用 React 编写的组件的示例git
使用 Chrome 的 DevTools 和 Lighthouse 来模拟 3G 网络下加载未登陆主页,结果显示未登陆主页须要 7 秒时间来加载,这段时间对于一个简单的入口页面来讲实在是过久了,因此咱们开始调查改进的可能性。经过一些性能审查,Netflix 发现他们的客户端 JS 有太高的开销。github
经过 Chrome DevTools 的网络限速功能,查看未优化的 Netflix.com 的表现。web
经过关闭浏览器中的 JavaScript 来观察站点中仍在起做用的元素,开发者团队能够决定 React 在未登陆主页是否真正必要。
因为页面中的多数元素是基本的 HTML,剩下的元素好比 JavaScript 点击处理和添加类能够用原生 JavaScript 来替换,而页面原来使用 React 实现的语言切换器则使用不到 300 行的原生 JavaScript 代码重构。
移植到原生 JavaScript 的组件彻底列表:
虽然 React 的初始代码仅仅 45 KB,在客户端移除 React、一些库和相应的 App 代码减小的 JavaScript 代码总量超多 200 KB,由此在 Netflix 的未登陆主页下降了超过 50% 的可交互时间。
移除客户端 React、Lodash 和其余一些库先后的负载比较。
在实验环境下,咱们可使用 Lighthouse(trace)快速测验用户是否能与 Netflix 主页交互。结果桌面端的 TTI 少于 3.5s。
可交互时间优化后的 Lighthouse 报告。
那么这个领域的度量标准呢?使用 Chrome 用户体验报告咱们能够看到首次输入延迟 —— 从用户首次与你的站点交互时间到浏览器真正响应那次交互的时间 —— 对于 97% 的 Netflix 桌面用户来讲很快。结果很是棒。
首先输入延迟(FID)度量用户在与页面交互时的延迟体验。
为了进一步提升浏览登陆主页的性能,Netflix 利用用户在入口页面上花费的时间针对可能会登陆的下一个页面进行资源预加载。
经过两项技术完成 —— 内置的 <link rel=prefetch>
浏览器 API 和 XHR 预加载。
内置的浏览器 API 包含页面头部标签内的简单连接标签。它会建议浏览器资源(例如 HTML、JS、CSS、图片)能够被预加载,虽然它并不保证浏览器真的会预加载资源,而且它缺乏其余浏览器的全面支持。
预加载技术对比
另外一方面,XHR 预加载已经成为浏览器标准不少年了,当 Netflix 团队提示浏览器缓存资源时,其成功率达到 95%。可是 XHR 预加载不能预加载 HTML 文档,Netflix 用它来为后续页面预加载 JavaScript 和 CSS 打包文件。
注意:Netflix 配置的 HTTP 响应头禁止使用 XHR 缓存 HTML(它们确实不缓存(no-cache)第二个页面的 HTML)。连接预加载会按预期工做,由于它对 HTML 有效,即便设置了不缓存(no-cache)。
// 建立新的 XHR 请求
const xhrRequest = new XMLHttpRequest();
// open the request for the resource to "prefetch"
// 打开请求来“预加载”资源
xhrRequest.open('GET', '../bundle.js', true);
// 发送!
xhrRequest.send();
复制代码
经过使用浏览器内置 API 和 XHR 预加载 HTML、CSS 和 JS,可交互时间减小了 30%。这个实现不须要重写 JavaScript,也不会对未登陆主页的性能形成负面影响,并且今后之后,能以极低的风险为提高页面性能提供了很是有价值的工具。
预加载实现以后,Netflix 开发者能够经过分析页面减小的可交互时间数据来观察性能提高效果,一样使用 Chrome 开发工具直接度量资源缓存的命中状况。
经过预加载 Netflix 未登陆主页资源和优化客户端代码,Netflix 能够在注册过程当中出色地提高可交互时间指标。经过使用浏览器内置 API 和 XHR 预加载来预获取将来页面,Netflix 能够把可交互时间下降 30%。这是针对下一页面的加载,其中包含单页应用注册过程的引导代码。
Netflix 团队进行的代码优化代表,React 是一个十分有用的库,不过它可能没法为每一个问题提供足够的解决方案。经过从第一个用于注册的入口页面的客户端代码中删除 React,可交互时间减小了 50% 以上。缩短客户端上的可交互时间还可让用户以更快地速度单击注册按钮,这代表代码优化彻底能够带来更好的用户体验。
虽然 Netflix 没有在主页中使用 React,但他们为后续的页面预加载。这使得他们整个页面应用程序流程中的其余部分能够利用客户端 React。
更多关于这些优化的细节,请观看 Tony Edwards 的出色演讲:
经过密切关注 JavaScript 的开销,Netflix 发现了改善可交互时间的机会。若想发现你的站点是否有机会在这点上作得更好,能够借助你的性能工具。
Netflix 决定作出的权衡是使用 React 对入口页面进行服务器渲染,同时也在其上预先获取 React 和其他注册流程的代码。这样能够优化首次加载性能,同时还能够优化其他注册流的加载时间,由于它是一个单页应用程序,所以须要下载更大的 JS 打包文件。
考虑一下是否使用原生 JavaScript 是否适合你的站点的流程。若是你确实须要使用库,那么尝试只嵌入你的用户须要的代码。预加载技术能够帮助优化将来浏览页面的加载时间。
感谢 Netflix UI 工程师,Tony Edwards、Ryan Burgess、Brian Holt、Jem Young、Kristofer Baxter(Google)、Nicole Sullivan(Chrome)和 Houssein Djirdeh(Chrome)的审阅和贡献。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。