提纲:Web 性能优化没有银弹。简单的静态网页得益于使用极少 JavaScript 代码的服务端渲染。库的谨慎使用可以为复杂的页面带来巨大的价值。
Netflix 是最受欢迎的视频流服务之一。自 2016 年在全球推出以来,公司发现许多新用户不仅通过移动设备完成注册,而且还使用了不太理想的网络连接。
通过改进用于Netflix.com 注册过程 JavaScript 代码和使用预加载技术,开发人员团队可以为移动和桌面用户提供更好的用户体验,并提供多项改进。
- 减少 50% 的加载和可交互时间(适用于Netflix.com 桌面端未登录的主页)
- 通过把 React 和其他客户端库改为原生的 JavaScript 使打包大小减少 200 KB。React 仍在服务端使用
- 为将来的操作预获取 HTML,CSS 和 JavaScript(React)使可交互时间减少 30%
通过嵌入更少的代码来减少可交互时间
Netflix 开发者优化性能的地方是未登录主页,用户在此页面注册并登录站点。
新用户和已登出用户的Netflix.com 主页
此页面初始包含 300KB 的 JavaScript 代码,其中一些是 React 和其他客户端代码(例如像 Lodash 的工具库),而且还有一些是必要的上下文数据用来给 React 的状态注水(hydrate)。
所有 Netflix 的网页都由服务端 React 渲染,这些页面为生成的 HTML 和客户端应用提供服务,因此维持新优化的主页结构不变和保持开发人员体验的一致性同样重要。
Homepage 选项卡是最初使用 React 编写的组件的示例
使用 Chrome 的 DevTools 和 Lighthouse 来模拟 3G 网络下加载未登录主页,结果显示未登录主页需要 7 秒时间来加载,这段时间对于一个简单的入口页面来说实在是太久了,所以我们开始调查改进的可能性。通过一些性能审查,Netflix 发现他们的客户端 JS 有过高的开销。
通过 Chrome DevTools 的网络限速功能,查看未优化的Netflix.com 的表现。
通过关闭浏览器中的 JavaScript 来观察站点中仍在起作用的元素,开发者团队可以决定 React 在未登录主页是否真正必要。
由于页面中的多数元素是基本的 HTML,剩下的元素比如 JavaScript 点击处理和添加类可以用原生 JavaScript 来替换,而页面原来使用 React 实现的语言切换器则使用不到 300 行的原生 JavaScript 代码重构。
移植到原生 JavaScript 的组件完全列表:
- 基础交互(主页中的选项卡)
- 语言切换器
- Cookie 横幅(针对非美国访问者)
- 分析用的客户端日志
- 性能评估和记录
- 广告来源引导代码(出于安全考虑,沙盒化放在 iframe 里)
虽然 React 的初始代码仅仅 45 KB,在客户端移除 React、一些库和相应的 App 代码 减少的 JavaScript 代码总量超多 200 KB ,由此在 Netflix 的未登录主页降低了超过 50% 的可交互时间。
移除客户端 React、Lodash 和其他一些库前后的负载比较。
在实验环境下,我们可以使用Lighthouse(trace)快速测验用户是否能与 Netflix 主页交互。结果桌面端的 TTI 少于 3.5s。
可交互时间优化后的 Lighthouse 报告。
那么这个领域的度量标准呢?使用Chrome 用户体验报告我们可以看到首次输入延迟 —— 从用户首次与你的站点交互时间到浏览器真正响应那次交互的时间 —— 对于 97% 的 Netflix 桌面用户来说很快。结果非常棒。
首先输入延迟(FID)度量用户在与页面交互时的延迟体验。
为后续页面预加载 React
为了进一步提高浏览登录主页的性能,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 未登录主页资源和优化客户端代码,Netflix 可以在注册过程中出色地提升可交互时间指标。通过使用浏览器内置 API 和 XHR 预加载来预获取未来页面,Netflix 可以把可交互时间降低 30%。这是针对下一页面的加载,其中包含单页应用注册过程的引导代码。
Netflix 团队进行的代码优化表明,React 是一个十分有用的库,不过它可能无法为每个问题提供足够的解决方案。通过从第一个用于注册的入口页面的客户端代码中删除 React,可交互时间减少了 50% 以上。缩短客户端上的可交互时间还可以让用户以更快地速度单击注册按钮,这表明代码优化完全可以带来更好的用户体验。
虽然 Netflix 没有在主页中使用 React,但他们为后续的页面预加载。这使得他们整个页面应用程序流程中的其他部分可以利用客户端 React。
更多关于这些优化的细节,请观看 Tony Edwards 的出色演讲:
- YouTube 视频链接:youtu.be/V8oTJ8OZ5S0
总结
通过密切关注 JavaScript 的开销,Netflix 发现了改善可交互时间的机会。若想发现你的站点是否有机会在这点上做得更好,可以借助你的性能工具。
Netflix 决定做出的权衡是使用 React 对入口页面进行服务器渲染,同时也在其上预先获取 React 和其余注册流程的代码。这样可以优化首次加载性能,同时还可以优化其余注册流的加载时间,因为它是一个单页应用程序,因此需要下载更大的 JS 打包文件。
考虑一下是否使用原生 JavaScript 是否适合你的站点的流程。如果你确实需要使用库,那么尝试只嵌入你的用户需要的代码。预加载技术可以帮助优化未来浏览页面的加载时间。
本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
对web开发技术感兴趣的同学,欢迎加入Q群:943129070,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。
网友评论