在 2018 年 Google IO 大会上,我们介绍了一系列工具、库和优化技术,可帮助您更轻松地提升网站性能。在本视频中,我们将使用 Oodles Theater 应用来介绍这些功能。我们还将介绍我们在预测性加载和新版 Guess.js 计划方面的实验。
过去一年来,我们一直在努力寻找如何让网络变得更快、性能更出色的方法。这促成了我们在本文中与您分享的新工具、方法和库。在第一部分,我们将向您展示在开发 Oodles Theater 应用时实际使用的一些优化技术。在第二部分,我们将介绍我们对预测性加载和新 Guess.js 计划开展的实验。
对性能的需求
互联网每年都在变得越来越庞大。如果我们查看网络状况,就会发现移动设备上的网页平均大小约为 1.5MB,其中大部分是 JavaScript 和图片。
网站不断增大,再加上网络延迟时间、CPU 限制、呈现阻塞模式或多余的第三方代码等其他因素,都导致了复杂的性能难题。
大多数用户将速度评为其体验需求层次结构中的首要因素。这并不奇怪,因为在网页加载完成之前,您实际上无法执行太多操作。您无法从该页面中获得价值,也无法欣赏其美感。
![用户体验层次结构金字塔](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/ux-hierarchy-piramide-9a38f1858336f.png?hl=zh-cn)
我们知道,效果对用户至关重要,但在确定从哪里着手进行优化时,您可能也感到一头雾水。幸运的是,有一些工具可以帮助您完成这项工作。
Lighthouse - 性能工作流的基础
Lighthouse 是 Chrome 开发者工具的一部分,可让您对网站进行审核,并提供有关如何改进网站的提示。
我们最近推出了一系列新的性能审核,这些审核在日常开发工作流中非常有用。
![新的 Lighthouse 评估](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/new-lighthouse-audits-a5c01f6ee0cf4.png?hl=zh-cn)
我们通过一个实用示例来探索如何利用这些功能:Oodles Theater 应用。这是一个小型演示版 Web 应用,您可以在其中试用一些我们喜爱的互动式 Google 涂鸦,甚至可以玩一两款游戏。
在构建应用时,我们希望确保其性能尽可能出色。优化的起点是 Lighthouse 报告。
![Oodles 应用的 Lighthouse 报告](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/lighthouse-report-oodles-04ce89ae09ebc.png?hl=zh-cn)
从 Lighthouse 报告中可以看出,我们应用的初始性能非常糟糕。 在 3G 网络上,用户需要等待 15 秒才能看到首次有意义的绘制,或者应用才能变为交互状态。Lighthouse 突出指出了我们网站存在的大量问题,而总体性能得分为 23 也正反映了这一点。
该网页的重量约为 3.4MB,我们迫切需要精简一些内容。
这引发了我们面临的第一个性能挑战:找出可以轻松移除且不会影响整体体验的内容。
性能优化建议
移除不必要的资源
有些明显的内容可以放心地移除:空格和注释。
![缩减带来的好处](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/gains-minification-209064021d2a2.png?hl=zh-cn)
Lighthouse 会在未压缩的 CSS 和 JavaScript 审核中突出显示此优化建议。我们在构建过程中使用了 webpack,因此为了进行缩减,我们只需使用 Uglify JS 插件即可。
缩减是常见任务,因此您应该能够找到适用于您所用 build 流程的现成解决方案。
该领域的另一项实用审核是启用文本压缩。没有理由发送未压缩的文件,而且目前大多数 CDN 都支持开箱即用。
我们使用 Firebase Hosting 托管代码,而 Firebase 默认启用 gzip 压缩,因此只需在合适的 CDN 上托管代码,我们就可以免费获得压缩功能。
虽然 gzip 是一种非常流行的压缩方式,但 Zopfli 和 Brotli 等其他机制也越来越受欢迎。大多数浏览器都支持 Brotli,您可以在将资源发送到服务器之前使用二进制文件对其进行预压缩。
使用高效的缓存政策
我们的下一步是确保在不必要的情况下不会重复发送资源。
Lighthouse 中的缓存效率不佳政策审核帮助我们发现,我们可以优化缓存策略,以实现这一目标。通过在服务器中设置 max-age 过期标头,我们确保用户在重复访问时可以重复使用之前下载的资源。
理想情况下,您应力求以最安全的方式缓存尽可能多的资源,并提供验证令牌,以便高效地重新验证已更新的资源。
移除未使用的代码
到目前为止,我们移除了不必要下载内容中的明显部分,但不太明显的部分呢?例如,未使用的代码。
![开发者工具中的代码覆盖率](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/code-coverage-devtools-d9d9ad4c8416d.png?hl=zh-cn)
有时,我们会在应用代码中添加一些实际上并不必要的代码。如果您在应用上投入较长时间,团队或依赖项发生变化,有时就会遗漏孤儿库,这时就需要进行清理。我们就遇到了这种情况。
最初,我们使用 Material Components 库快速制作了应用的原型。随着时间的推移,我们改用更具自定义外观和风格的设计,完全忘记了该库。幸运的是,代码覆盖率检查帮助我们在软件包中重新发现了它。
您可以在 DevTools 中查看应用的运行时和加载时间的代码覆盖率统计数据。您可以在下方的屏幕截图中看到两个大红条 - 我们的 CSS 有超过 95% 未使用,JavaScript 也是如此。
Lighthouse 在未使用的 CSS 规则审核中也发现了此问题。结果显示,潜在节省量超过 400kb。因此,我们返回到了代码,并移除了该库的 JavaScript 和 CSS 部分。
![如果我们移除 MVC 适配器,我们的样式会缩减到 10KB](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/if-drop-mvc-adapter-sty-f311da23542ff.png?hl=zh-cn)
这样一来,我们的 CSS 软件包就缩小了 20 倍,对于一个只有两行代码的小型提交来说,这已经相当不错了。
当然,这提高了我们的性能得分,也显著缩短了互动所需时间。
不过,对于此类变化,仅查看指标和得分是不够的。移除实际代码绝非没有风险,因此您应始终注意可能出现的回归问题。
95% 的代码都没有用到,但仍有 5% 的代码在某个地方用到了。显然,我们的一个组件仍在使用该库中的样式,即涂鸦滑块中的小箭头。不过,由于它很小,我们可以手动将这些样式重新整合到按钮中。
![由于缺少库,按钮无法正常使用](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/buttons-got-broken-missi-6e2d05b1a4f04.png?hl=zh-cn)
因此,如果您移除代码,只需确保您已建立适当的测试工作流,以帮助您防范可能出现的视觉回归问题。
避免网络载荷过大
我们知道,大型资源可能会减慢网页加载速度。这可能会给用户带来费用,并对其流量套餐产生重大影响,因此请务必注意这一点。
Lighthouse 使用网络载荷过大审核功能检测到,我们的某些网络载荷存在问题。
![检测巨大的网络载荷](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/detect-enormous-network-p-b417c0f85336d.png?hl=zh-cn)
在这里,我们发现有超过 3MB 的代码要下发,这非常多,尤其是在移动设备上。
在列表顶部,Lighthouse 突出显示了我们的 JavaScript 供应商软件包包含 2MB 的未压缩代码。这也是 webpack 强调的问题。
俗话说:最快的请求是根本不发出请求。
理想情况下,您应衡量向用户分发的每个资源的价值,衡量这些资源的效果,并确定是否值得将其实际分发到初始体验中。因为有时这些资源可以延迟加载或延迟处理,也可以在空闲时间处理。
在我们的示例中,由于我们要处理大量 JavaScript 软件包,因此很幸运的是,JavaScript 社区提供了丰富的 JavaScript 软件包审核工具。
![JavaScript 软件包审核](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/javascript-bundle-auditin-bb72c40c2152f.png?hl=zh-cn)
我们首先使用了 webpack bundle analyzer,它告知我们,我们包含了一个名为 unicode 的依赖项,该依赖项包含 1.6MB 的解析 JavaScript,因此非常大。
然后,我们转到了编辑器,使用 Visual Studio Code 的导入成本插件,能够直观地查看我们要导入的每个模块的成本。这样,我们就可以发现哪个组件包含引用此模块的代码。
然后,我们改用另一种工具 BundlePhobia。借助此工具,您可以输入任何 NPM 软件包的名称,并实际查看其经过缩减和压缩后的估算大小。我们找到了一个非常适合我们使用的仅 2.2kb 的 Slug 模块替代方案,因此改用该模块。
这对我们的广告效果产生了很大影响。在进行这项更改并发现其他缩减 JavaScript 软件包大小的机会后,我们节省了 2.1MB 的代码。
考虑到这些软件包经过 GZIP 压缩和缩减后的大小,我们总体上实现了 65% 的改进。 我们发现,这确实是一个值得做的流程。
因此,一般来说,请尽量减少网站和应用中的不必要下载。对素材资源进行清点并衡量其对效果的影响会产生很大的影响,因此请务必定期审核素材资源。
通过代码拆分缩短 JavaScript 启动时间
虽然较大的网络载荷可能会对应用产生重大影响,但还有另一个因素可能会产生非常大的影响,那就是 JavaScript。
JavaScript 是最昂贵的资源。在移动设备上,如果您发送大量的 JavaScript 软件包,可能会延迟用户与界面组件互动的速度。这意味着,用户可以点按界面,但实际上不会发生任何有意义的事情。因此,我们有必要了解 JavaScript 开销如此之高的原因。
浏览器就是这样处理 JavaScript 的。
![JavaScript 处理](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/javascript-processing-a88df8122641b.png?hl=zh-cn)
首先,我们必须下载该脚本,然后我们有一个 JavaScript 引擎,该引擎需要解析该代码,需要编译并执行该代码。
现在,在高端设备(例如台式机、笔记本电脑,甚至高端手机)上,这些阶段所需的时间并不多。但在平均水平的手机上,此过程可能需要多 5 到 10 倍的时间。这会延迟互动,因此我们必须尽量缩减此类内容。
为帮助您发现应用存在的这些问题,我们在 Lighthouse 中引入了新的 JavaScript 启动时间审核。
![JavaScript 启动时间](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/javascript-boot-time-d9ae37a556e82.png?hl=zh-cn)
在 Oodle 应用的情况下,它告诉我们 JavaScript 启动花费了 1.8 秒的时间。当时的情况是,我们将所有路由和组件静态导入到一个单体 JavaScript 软件包中。
解决此问题的一种方法是使用代码分块。
![代码拆分就像披萨](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/code-splitting-is-pizza-6008484e57adc.png?hl=zh-cn)
代码分块的概念是,如果您根据用户的需求,一次只向他们提供一个比萨饼片的 JavaScript,而不是一次性提供整个比萨饼,那会怎么样?
代码拆分可在路线级别或组件级别应用。它非常适合与 React 和 React Loadable、Vue.js、Angular、Polymer、Preact 和许多其他库搭配使用。
我们将代码分块功能纳入了应用,并从静态导入切换到了动态导入,从而能够根据需要异步延迟加载代码。
![使用动态导入进行代码拆分](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/code-splitting-dynamic-i-bef50644cc8ac.png?hl=zh-cn)
这不仅缩减了软件包的大小,还缩短了 JavaScript 启动时间。缩短到 0.78 秒,使应用的运行速度提高了 56%。
一般来说,如果您要构建大量使用 JavaScript 的体验,请务必仅向用户发送他们需要的代码。
充分利用代码分块等概念,探索树摇动等想法,并查看 webpack-libs-optimizations 代码库,了解如何缩减库大小(如果您恰好使用 webpack)。
优化图像
![图片加载性能玩笑](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/image-loading-performance-82f3792c437f6.png?hl=zh-cn)
在 Oodle 应用中,我们使用了大量图片。很遗憾,Lighthouse 对此的热情远不如我们。事实上,我们在与图片相关的所有三项审核中都未通过。
我们忘了优化图片,没有正确调整图片大小,而且可以通过使用其他图片格式获得一些收益。
![图片审核](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/image-audits-719c8447f8aaf.png?hl=zh-cn)
我们首先优化了图片。
对于一次性优化,您可以使用 ImageOptim 或 XNConvert 等可视化工具。
更自动化的方法是使用 imagemin 等库,将图片优化步骤添加到构建流程中。
这样,您就可以确保日后添加的图片会自动进行优化。某些 CDN(例如 Akamai)或第三方解决方案(例如 Cloudinary、Fastly 或 Uploadcare)可为您提供全面的图片优化解决方案,因此您也可以直接在这些服务上托管图片。
如果您不想这样做,因为成本或延迟问题,Thumbor 或 Imageflow 等项目提供了自托管替代方案。
![优化前后](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/before-after-optimizatio-45b3bbf20acca.png?hl=zh-cn)
我们的背景 PNG 在 webpack 中被标记为大小过大,这是正确的。在将其正确调整为视口大小并通过 ImageOptim 运行后,我们将其缩减到了 100kb,这是一个可接受的大小。
对我们网站上的多张图片重复执行此操作后,我们成功大幅降低了网页的总体权重。
使用适合动画内容的格式
GIF 的费用可能非常高昂。令人惊讶的是,GIF 格式从一开始就不是用作动画平台的。因此,改用更合适的视频格式可以大幅缩减文件大小。
在 Oodle 应用中,我们在首页上使用 GIF 作为片头序列。根据 Lighthouse 的说法,如果改用更高效的视频格式,我们可以节省超过 7MB 的空间。我们的剪辑大小约为 7.3MB,对于任何合理的网站来说都太大了,因此我们将其转换为一个视频元素,并添加了两个源文件(一个 MP4 文件和一个 WebM 文件),以便获得更广泛的浏览器支持。
![将动画 GIF 替换为视频](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/replace-animated-gifs-vi-fc084e0a3fb4e.png?hl=zh-cn)
我们使用 FFmpeg 工具将动画 GIF 转换为 mp4 文件。WebM 格式可让您节省更多空间 - ImageOptim API 可以为您执行此类转换。
ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4
得益于这种转换,我们总体重量减少了 80% 以上。这样一来,我们就缩减到了大约 1MB。
不过,1MB 还是一个很大的资源,尤其是对于带宽受限的用户。幸运的是,我们可以使用 Effective Type API 来了解用户的带宽较慢,并改为向他们提供体积小得多的 JPEG。
此接口使用有效往返时间和下载值来估算用户使用的网络类型。它只会返回一个字符串,即“2G 网络信号较弱”“2G”“3G”或“4G”。因此,如果用户使用的是低于 4G 的网络,我们可以根据此值将视频元素替换为图片。
if (navigator.connection.effectiveType) { ... }
这确实会影响用户体验,但至少在连接速度缓慢时,用户仍可使用该网站。
延迟加载屏幕外图片
轮播界面、滑块或非常长的网页通常会加载图片,即使用户无法立即在网页上看到这些图片也是如此。
Lighthouse 会在屏幕外图片审核中标记此行为,您也可以在 DevTools 的“Network”(网络)面板中自行查看。如果您看到大量图片正在传入,但网页上只显示了少数图片,则表示您不妨考虑改为延迟加载图片。
浏览器尚不支持原生延迟加载,因此我们必须使用 JavaScript 来添加此功能。我们使用了 Lazysizes 库为 Oodle 封面添加了延迟加载行为。
<!-- Import library -->
import lazysizes from 'lazysizes' <!-- or -->
<script src="lazysizes.min.js"></script>
<!-- Use it -->
<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
data-sizes="auto"
data-src="image2.jpg"
data-srcset="image1.jpg 300w,
image2.jpg 600w,
image3.jpg 900w"/>
Lazysizes 非常智能,因为它不仅会跟踪元素的显示状态变化,还会主动预提取靠近该视图的元素,以提供最佳用户体验。它还提供了可选的 IntersectionObserver
集成,可让您非常高效地查询可见性。
此项更改生效后,我们的图片将按需提取。如果您想深入了解该主题,请参阅 images.guide,这是一个非常实用且全面的资源。
帮助浏览器尽早提交关键资源
并非通过网络传送到浏览器的每个字节都具有相同的重要性,浏览器也知道这一点。许多浏览器都采用启发词语来决定应先提取哪些内容。因此,有时它们会先提取 CSS,然后再提取图片或脚本。
作为网页的作者,我们可以告知浏览器哪些内容对我们来说非常重要,这可能会很有用。值得庆幸的是,在过去几年里,浏览器供应商一直在添加一些功能来帮助我们实现这一点,例如 link rel=preconnect
、preload
或 prefetch
等资源提示。
这些功能为 Web 平台带来了一些帮助,可让浏览器在适当的时间提取正确的内容,并且比使用脚本完成的一些基于逻辑的自定义加载方法效率略高。
我们来看看 Lighthouse 实际上如何引导我们有效使用其中的一些功能。
Lighthouse 告知我们要做的第一件事是避免多次往返任何来源,因为这会产生高昂的费用。
![避免多次往返任何来源,这会产生高昂的费用](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/avoid-multiple-costly-ro-1349e14da4d4d.png?hl=zh-cn)
在 Oodle 应用中,我们实际上大量使用了 Google Fonts。每当您将 Google Fonts 样式表放入网页时,它都会连接到两个子网域。Lighthouse 告诉我们,如果能够预热该连接,我们最多可以缩短 300 毫秒的初始连接时间。
利用链接 rel 预连接,我们可以有效掩盖这种连接延迟。
尤其是对于 Google Fonts 等资源,我们的字体 CSS 托管在 googleapis.com 上,而字体资源托管在 Gstatic 上,这可能会产生很大的影响。因此,我们应用了此优化,缩短了几百毫秒的时间。
Lighthouse 的下一个建议是预加载关键请求。
![预加载密钥请求](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/preload-key-requests-a2751a962b7e2.png?hl=zh-cn)
<link rel=preload>
非常强大,它会通知浏览器当前导航需要某个资源,并尝试让浏览器尽快提取该资源。
现在,Lighthouse 告诉我们,由于我们要加载两个 Web 字体,因此应预加载关键的 Web 字体资源。
在 Web 字体中预加载的代码如下所示:指定 rel=preload
后,您将 as
与字体类型一起传入,然后指定您尝试加载的字体类型,例如 woff2。
这对您的网页的影响非常明显。
![预加载资源的影响](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/impact-preloading-resour-d6cf8908f75e3.png?hl=zh-cn)
通常,如果网页字体对您的网页至关重要,而您未使用 link rel preload,那么浏览器必须先提取 HTML 并解析 CSS,然后在很久之后才会提取网页字体。
使用 link rel preload 后,浏览器在解析您的 HTML 后,实际上可以更早地开始提取这些 Web 字体。在我们的应用中,这可以将使用 Web 字体渲染文本所需的时间缩短一秒。
现在,如果您尝试使用 Google Fonts 预加载字体,则会遇到一个问题,事情并非那么简单。
我们在样式表中为字体指定的 Google 字体网址恰好是字体团队经常更新的内容。这些网址可能会过期或定期更新,因此,如果您想完全控制字体加载体验,我们建议您自行托管 Web 字体。这非常有用,因为它可以让您使用链接 rel preload 等功能。
在我们的案例中,我们发现 Google Web Fonts Helper 非常有用,它可以帮助我们离线使用某些 Web 字体并在本地进行设置,因此请试用该工具。
无论您是将 Web 字体作为关键资源的一部分,还是将 JavaScript 作为关键资源,请尽量帮助浏览器尽快提供关键资源。
实验性功能:优先级提示
今天,我们有特别的内容要与您分享。除了资源提示和预加载等功能之外,我们还在开发一项全新的实验性浏览器功能,我们称之为“优先级提示”。
![为最初可见的内容设置优先级](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/set-priority-the-initial-a002f3faeabf3.png?hl=zh-cn)
这项新功能可让您向浏览器提示资源的重要性。它会公开一个新属性 - importance,其值为 low、high 或 auto。
这样,我们就可以降低不太重要的资源(例如非关键样式、图片或提取 API 调用)的优先级,以减少争用。我们还可以提高重要内容(例如主推图片)的优先级。
在我们的 Oodle 应用中,这实际上让我们发现了一个可优化的实际位置。
![为最初可见的内容设置优先级](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/set-priority-the-initial-b31819a78b75c.png?hl=zh-cn)
在为图片添加延迟加载之前,浏览器的做法是,我们有一个包含所有涂鸦的图片轮播界面,浏览器会在轮播界面开始时以高优先级提取所有图片。遗憾的是,对用户而言,轮播界面中间部分的图片才是最重要的。我们将这些背景图片的重要性设为非常低,前景图片的重要性设为非常高,这样一来,在 3G 网络速度缓慢的情况下,我们能够在 2 秒内提取和渲染这些图片。因此,这是一个非常好的积极体验。
我们希望在几周内将此功能引入 Canary 版,敬请期待。
制定网页字体加载策略
排版是优质设计的基础,如果您使用的是 Web 字体,最好不要阻止文本呈现,也绝对不要显示不可见的文本。
现在,我们在 Lighthouse 中通过避免在网页字体加载期间显示不可见文本审核来突出显示这一点。
![避免在网页字体加载期间显示不可见文本](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/avoid-invisible-text-whil-d461292533245.png?hl=zh-cn)
如果您使用字体样式块加载网页字体,则表示您让浏览器决定在网页字体提取花费很长时间时该怎么做。某些浏览器会等待最多三秒钟,然后才会回退到系统字体,并最终在下载字体后将其替换为该字体。
我们会尽量避免这种不可见的文字,因此在本例中,如果网络字体加载时间过长,我们将无法看到本周的经典涂鸦。幸运的是,借助名为 font-display
的新功能,您实际上可以更好地控制此过程。
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-display: swap;
font-weight: 400;
src: local('Montserrat Regular'), local('Montserrat-Regular'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('montserrat-v12-latin-regular.woff2') format('woff2'),
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
url('montserrat-v12-latin-regular.woff') format('woff');
}
字体显示有助于您根据 Web 字体切换所需的时间来决定 Web 字体的呈现方式或回退方式。
在本例中,我们使用的是字体显示切换。换行会为字体样式分配零秒的块周期和无限的换行周期。这意味着,如果字体需要一段时间才能加载,浏览器会立即使用后备字体绘制文本。字体可用后,系统会进行切换。
在我们的应用中,这样做非常有用,因为它让我们能够在很早的阶段显示一些有意义的文本,并在 Web 字体准备就绪后切换到 Web 字体。
![字体显示结果](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/font-display-outcome-a014081404b38.png?hl=zh-cn)
一般来说,如果您恰好使用的是网页字体(就像大部分网站所做的那样),请采用良好的网页字体加载策略。
您可以使用许多 Web 平台功能来优化字体的加载体验,但也请查看 Zach Leatherman 的 Web Font Recipes 代码库,因为它非常实用。
减少阻塞渲染的脚本
我们可以在下载链中的更早位置推送应用的其他部分,以便稍早提供一些基本的用户体验。
在 Lighthouse 时间轴条上,您可以看到,在所有资源加载的前几秒内,用户实际上看不到任何内容。
![减少阻塞渲染的样式表的机会](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/reduce-render-blocking-st-ee605dfe41336.png?hl=zh-cn)
下载和处理外部样式表会阻止渲染进程取得任何进展。
我们可以尝试提前一点提交一些样式,以优化关键渲染路径。
如果我们提取负责此初始呈现的样式并将其内嵌到 HTML 中,浏览器便可立即呈现这些样式,而无需等待外部样式表到达。
在我们的示例中,我们使用了一个名为 Critical 的 NPM 模块,在构建步骤期间将关键内容内嵌到 index.html 中。
虽然此模块为我们完成了大部分繁重工作,但要让其在不同路线上顺畅运行,仍然有点棘手。
如果您不小心或网站结构非常复杂,并且您从一开始就没有计划采用应用壳架构,那么引入此类模式可能非常困难。
因此,请务必尽早考虑性能问题。如果您从一开始就没有考虑性能,那么日后很可能会遇到性能问题。
最终,我们的冒险得到了回报,我们设法使其正常运行,应用开始提前提供内容,从而显著缩短了首次有效绘制时间。
结果
以上是我们对网站应用的一系列性能优化措施。我们来看看结果。这是我们的应用在 3G 网络上中型移动设备上的加载情况,优化前后对比。
Lighthouse 性能得分从 23 提高到了 91。速度上进步不错。我们之所以能够做出这些改变,是因为我们一直在持续检查和跟踪 Lighthouse 报告。如果您想了解我们是如何在技术层面实现所有改进的,欢迎随时查看我们的代码库,尤其是其中的 PR。
预测性效果 - 以数据为依据的用户体验
我们认为,机器学习在许多领域都代表着未来的巨大机遇。我们希望未来能激发更多实验的一个想法是,真实数据确实可以指导我们打造的用户体验。
目前,我们会根据用户可能想要或需要的内容做出许多任意决策,从而确定哪些内容值得预提取、预加载或预缓存。如果我们猜对了,可以优先处理少量资源,但很难将其扩展到整个网站。
我们目前已经有数据可供参考,以便更好地进行优化。使用 Google Analytics Reporting API,我们可以查看网站上任何网址的下一个热门网页和退出百分比,从而得出关于应优先处理哪些资源的结论。
如果将此方法与良好的概率模型相结合,我们就可以避免过度提前预加载内容,从而浪费用户的数据。我们可以利用这些 Google Analytics 数据,并使用机器学习和马尔可夫链或神经网络等模型来实现此类模型。
![适用于 Web 应用的数据驱动型捆绑](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/data-driven-bundling-web-3843c496c6e42.png?hl=zh-cn)
为了便于进行这些实验,我们很高兴地宣布推出一项名为 Guess.js 的新计划。
![Guess.js](https://web.developers.google.cn/static/articles/web-performance-made-easy/image/guessjs-8f7d906237584.png?hl=zh-cn)
Guess.js 是一个专注于为 Web 提供数据驱动型用户体验的项目。我们希望这有助于您探索如何利用数据来提升网站性能,并取得更理想的成效。所有这些都是开源的,目前已在 GitHub 上发布。该工具由 Minko Gechev、来自 Gatsby 的 Kyle Matthews、Katie Hempenius 等多位开源社区成员共同构建。
请查看 Guess.js,并告诉我们您的想法。
摘要
得分和指标有助于提高网站速度,但它们只是手段,而不是目标本身。
我们都曾遇到过移动设备上网页加载缓慢的情况,但现在,我们有机会为用户提供加载速度极快的更出色的体验。
提升广告效果是一项长期的任务。很多小变化可以带来巨大成效。通过使用合适的优化工具并密切关注 Lighthouse 报告,您可以为用户提供更好、更包容的体验。
特别感谢:Ward Peeters、Minko Gechev、Kyle Mathews、Katie Hempenius、Dom Farolino、Yoav Weiss、Susie Lu、Yusuke Utsunomiya、Tom Ankers、Lighthouse 团队和 Google 涂鸦团队。