Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级

阿里云最近在做活动,低至2折,有兴趣可以看看:
https://promotion.aliyun.com/...

为了保证的可读性,本文采用意译而非直译。

这是 Web 性能优化的第 6 篇,上一篇在下面看点击查看:

  1. Web 性能优化:使用 Webpack 分离数据的正确方法
  2. Web 性能优化:图片优化让网站大小减少 62%
  3. Web 性能优化:缓存 React 事件来提高性能
  4. Web 性能优化:21种优化CSS和加快网站速度的方法
  5. Web 性能优化:理解及使用 JavaScript 缓存

今天,我们将深入研究Chrome 的网络栈,以明确 web 加载原语(如<link rel= preload > & ) 背后的工作原理,以便你能够更有效地使用它们。

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!

如其他文章所述,preload 是一个声明式 fetch,可以强制浏览器在不阻塞 document 的 onload 事件的情况下请求资源。

Prefetch 告诉浏览器这个资源将来可能需要,但是什么时间加载这个资源是由浏览器来决定的。

在预加载(perload)之前,网络请求从这里开始,预加载之后,它在解析时从左向右移动

使用预加载(perload)的一些案例

在详细介绍 预加载(perload) 之前,先来看看一些使用 预加载(perload) 的案例。

Housing.com 在对他们的渐进式 Web 应用程序的脚本转用 proload 看到大约缩短了10%的可交互时间。

Shopify 使用 preload 加载 Web字体后,Chrome 桌面版)的文本绘制时间(1.2秒)提高了50%,这完全解决了他们的文字闪动问题。

左边:使用 preload,右边:不使用 preload

使用 加载字体

Treebo,印度最大的旅馆网站之一,在 3G 网络下对其桌面版试验,在对其顶部图片和主要的 Webpack 打包文件使用 preload 之后,在首屏绘制和可交互延迟分别减少了 1s。

同样的,在对自己的渐进式 Web 应用程序主要打包文件使用 preload 之后,Flipkart 在路由解析之前 节省了大量的主线程空闲时间(在 3G 网络下的低性能手机下)。

上面:没有使用 proload 加载,下面:使用 preload 加载

Chrome 数据保护程序团队发现,对于那些可以在脚本和 CSS 样式表上使用 preload 的页面,发现页面首次绘制时间获得平均 12% 的速度提升。

对于 prefetch(预读取),它被广泛使用,在 Google 我们仍用它来预读取一些可以加快 搜索结果页面 的渲染的关键资源。

Preload 在大型网站中都有很好运用,你可以在本文后面找到更多这些安全。 在此之前,让我们深入了解网络堆栈如何实际处理 预加载(prefetch)与预读取(prefetch)

何时使用

提示: preload 加载资源一般是当前页面需要的, prefetch 一般是其它页面有可能用到的资源。

preload 是告诉浏览器预先请求当前页面需要的资源(关键的脚本,字体,主要图片等)。

prefetch 应用场景稍微又些不同 —— 用户将来可能跳转到其它页面需要使用到的资源。如果 A 页面发起一个 B 页面的 prefetch 请求,这个资源获取过程和导航请求可能是同步进行的,而如果我们用 preload 的话,页面 A 离开时它会立即停止。

preloadprefetch 之间,我们对当前页面或即将跳转的页面在所需主要资源的问题有了一个解决方案。

的缓存行为

当资源被 preload 或者 prefetch 后,会从网络堆栈传输到 HTTP 缓存并进入渲染器的内存缓存。 如果资源可以被缓存(例如,存在有效的 cache-control 和 max-age),它将存储在 HTTP 缓存中,可用于当前和未来的会话。 如果资源不可缓存,则不会将其存储在 HTTP 缓存中。 相反,它会被缓存到内存缓存中并保持不变直到它被使用。

Chrome 的网络栈中是如何处理 preload 和 prefetch 的优先级?

下面是在 Blink 内核的 Chrome 46 及更高版本中不同资源的加载优先级情况著作权归作者所有。

preload 用 “as” 或者用 “type” 属性来表示他们请求资源的优先级(比如说 preload 使用 as="style" 属性将获得最高的优先级)。没有 “as” 属性的将被看作异步请求,“Early”意味着在所有未被预加载的图片请求之前被请求(“late”意味着之后)

我们来谈一下这张表。

脚本根据它们在文件中的位置是否异步、延迟或阻塞获得不同的优先级:

  • 网络在第一个图片资源之前阻塞的脚本在网络优先级中是中级
  • 网络在第一个图片资源之后阻塞的脚本在网络优先级中是低级
  • 异步/延迟/插入的脚本(无论在什么位置)在网络优先级中是很低级

图像在可视窗口中比不在视口中的图像(具有更高的优先级,因此在某种程度上, Chrome 将会尽量懒加载这些不在视口中的图片。 较低优先级的图片出现在视口中时,该图片的优先级就会得到提升(但是注意已经在布局完成后的图片优先级不会在更改)。

使用“as”属性预加载的资源将具有与它们请求的资源类型相同的资源优先级。 例如,preload as =“style”将获得最高优先级,而as =“script”将获得低优先级或中优先级。 这些资源也遵循相同的CSP策略(例如脚本受 script-src 约束)。

不带 “as” 属性的 preload 的优先级将会等同于异步请求。

如果你想了解各种资源加载时的优先级属性,从开发者工具的 Timeline/Performance 区域的 Network 区域都能看到相关信息:

在 Network 面板下的 “Priority” 部分

当页面 preload 已经在 Service Worker 缓存及 HTTP 缓存中的资源时会发生什么?

这各情况来说是比较少的,但通常来说,会是比较好的情况 —— 如果资源没有超出 HTTP 缓存时间或者 Service Worker 没有主动重新发起请求,那么浏览器就不会再去请求这个资源了。

如果资源在 HTTP 缓存中(在SW缓存和网络之间),那么 preload 会从相同的资源中获得缓存命中。

这种加载方式会浪费用户的带宽吗

使用 preload 或 prefetch,可能会浪费用户的带宽,特别是在资源没有缓存的情况下。

没有用到的 preload 资源在 Chrome 的 console 里会在 onload 事件 3s 后发生警告。

这个警告的原因是,你可能正在使用preload来尝试为其他资源预加载并缓存以提高性能,但是如果这些预加载的资源没有被使用,那么你就在毫无理由地做额外的工作。在移动设备上,这相当于浪费用户的流量,所以要注意预加载的内容。

什么情况会导致二次获取?

preloadprefetch 是很简单的工具,你很容易不小心二次获取。

不要用 “prefetch” 作为 “preload” 的后备方案 ,它们适用于不同的场景,常常会导致不符合预期的二次获取。使用 preload 来获取当前需要任务否则使用 prefetch 来获取将来的任务,不要一起用。

对 preload 使用 “as” 属性,不然将不会从中获益。

如果在指定要 preload 的内容(例如脚本)时未提供有效的“as”,则最终将获取两次。

preload 字体不带 crossorigin 也将会二次获取, 确保在使用 preload 获取字体时添加crossorigin 属性,否则将二次下载。 他这个请求使用匿名的跨域模式。 即使字体与页面位于同个域 下,也建议使用。也适用于其他域名的获取(比如说默认的异步获取)。

最后,虽然它不会导致两次获取,但这通常是一个很好的建议:

不要所有的请求资源都加 preload,用 preload 来告诉浏览器一些很被需要的资源,以便让它提早获取它们。

我应当在页面头部所有的资源都加上 preload

这是工具的一个很好的例子,而不是规则。 preload 的文件数量取决于加载其他资源时网络内容、用户的带宽和其他网络状况。

尽早 preload 页面中可能需要的文件,对于脚本,preload 你的关键模块是很好的,因为它将获取与执行分开,而仅仅使用

你可能感兴趣的:(javascript,程序员,前端,web)