基础系列-preload与prefetch

有时候为了提高网页初始加载的性能,我们会选择延迟一部分资源的加载和执行。

另一种情况是我们想要尽早加载资源,但是要等到合适的时机再执行。时机的影响因素包括依赖关系、执行条件、执行顺序等。

通常的做法是:

  • 通过插入一个页面元素来声明一个资源(比如img、script、link)。这种方式会将资源的加载和执行耦合
  • 用AJAX来加载资源。这种方式只有在时机成熟时才会加载资源,解决了执行时机问题。但是浏览器无法预解析,也就无法提前加载。另外如果页面有大量的阻塞脚本,就会造成延迟

Resource Hints

即预获取, 指的是页面后续会与另外一个节点或者资源建立连接, 让浏览器可以在合适的时间进行提前获取, 减少用户与后续节点的连接时间。

  • preload
  • prefetch
  • preconnect

W3C:https://w3c.github.io/resource-hints/

深入阅读:https://www.keycdn.com/blog/resource-hints

Preload

浏览器支持情况:https://caniuse.com/#feat=link-rel-preload

即预加载,指的是页面资源加载的优先级,对最重要的资源最优先加载。专注于当前页面。

html 页面 head 中设置 link 标签的 rel="preload" 属性告诉浏览器当前页面哪些资源需要优先提取。可以作用多种资源。

<!-- preload stylesheet resource via declarative markup -->
<link rel="preload" href="/styles/base.css" as="style">
<link rel="preload" href="https://fonts.example.com/font.woff2" as="font" crossorigin type="font/woff2">

as属性:
该属性声明需要加载的资源类型, 以便浏览器可以正确处理该资源.
crossorigin属性:
对于开启CORS的资源, 需要添加crossorigin, 否则浏览器将无法正确加载此资源.

当浏览器“看”到这样的声明后,就会以一定的优先级在后台加载资源。加载完的资源放在HTTP缓存中。而等到要真正执行时,再按照正常方式用标签或者代码加载,即可从HTTP缓存取出资源。

通过网络发送到浏览器的每个字节并非都具有同等重要性,浏览器深谙此道。 浏览器采用启发式算法,尝试对首先要加载的最重要的资源作出最佳猜测,例如先加载 CSS 然后再加载脚本和图像。

即便如此,和任何启发式算法一样,这种方式并非总是有效;浏览器可能作出错误判断,原因通常在于当下获得的信息不足。 本文解释如何通过告知现代浏览器您稍后才需要的内容,充分影响浏览器中内容的优先级。

https://web.dev/fast/#prioritize-resources

浏览器预加载:浏览器预加载只预先加载在HTML中声明的资源。一旦html解析器到达资源,资源将被执行,对于何时执行资源没有灵活性。和 preload 指令不同。

特点

  • 提前加载资源
  • 资源的加载和执行分离
  • 不延迟网页的load事件(除非Preload资源刚好是阻塞 window 加载的资源)

好处

  • 允许浏览器来设定资源加载的优先级因此可以允许前端开发者来优化指定资源的加载。
  • 赋予浏览器决定资源类型的能力,因此它能分辨这个资源在以后是否可以重复利用。
  • 浏览器可以通过指定 as 属性来决定这个**请求是否符合 content security policy**。
  • 浏览器可以基于资源的类型(比如 image/webp)来发送适当的 accept 头。

应用

  • 在单页应用中,提前加载路由文件,提高切换路由时的渲染速度。现在大型的单页应用通常会异步加载路由文件。当用户切换路由时再异步加载相应的模块存在性能问题。可以用Preload提前加载,提升性能。
  • 提前加载字体文件。由于字体文件必须等到CSSOM构建完成并且作用到页面元素了才会开始加载,会导致页面字体样式闪动(FOUT,Flash of Unstyled Text)。所以要用Preload显式告诉浏览器提前加载。假如字体文件在CSS生效之前下载完成,则可以完全消灭FOUT。

参考链接:

有一种优化,叫Preload

preload-dirctive

Prefetch

是一个低优先级的资源提示,允许浏览器在后台(空闲时)获取将来可能用得到的资源,并且将他们存储在浏览器的缓存中。一旦一个页面加载完毕就会开始下载其他的资源,然后当用户点击了一个带有 prefetched 的连接,它将可以立刻从缓存中加载内容。

prefetch 有三种类型:link prefetching、dns-prefetch、prerender。

深入阅读:https://www.keycdn.com/support/prefetching

浏览器支持情况: https://caniuse.com/#feat=link-rel-prefetch

对后续访问的资源进行提前加载, 需要指明资源类型.

<link rel="prefetch" href="//example.com/next-page.html" as="document" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">

dns-prefetch

浏览器支持情况:https://caniuse.com/#feat=link-rel-dns-prefetch

对后续会访问的域名提前解析, 具体使用场景参考 #16

<link rel="dns-prefetch" href="//example.com">

不过要注意的是 Chrome 已经在敲击地址栏的时候做了类似的事情,比如 DNS preresolve 和 TCP preconnect,这些措施太酷了!你可以通过 chrome://dns/ 来查看你的优化列表。

prerender

浏览器支持情况:https://caniuse.com/#feat=link-rel-prerender

优化了可能导航到的下一页上的资源的加载,在后台渲染了整个页面和资源。即标识后续的导航页面, 下载资源并执行, 即预读取页面, 常用于分页功能。

<link rel="prerender" href="//example.com/next-page.html">

要小心的使用 prerender,因为它将会加载很多资源并且可能造成带宽的浪费,尤其是在移动设备上。还要注意的是,你无法在 Chrome DevTools 中进行测试,而是在 chrome://net-internals/#prerender 中看是否有页面被 prerendered 了,你也可以在 prerender-test.appspot.com 进行测试。

额外的副作用:

  • Web 统计将会收到影响而变大,尽管 Google 说已经限制了这个标签。看看这个关于页面分析将会被影响而在一次点击时产生两个 session 的 文章
  • 由于可能从未访问的站点下载了更多的页面(尤其是隐匿下载正在变得更加先进和多样化),用户的安全将面临更多的风险。
  • 如果预取访问未经授权的内容,用户可能违反其网络或组织的可接受使用策略。

proload 与 prefetch 的区别

  • Preload 作用在同一个请求页面的不同时段
  • Prefetch 作用与不同请求页面
  • Preload 是强制性指令, 浏览器必须按照这个指令进行执行.
  • Prefetch 是非强制性指令, 浏览器会决定是否运行此指令以及何时运行

preconnect

浏览器支持情况:https://caniuse.com/#feat=link-rel-preconnect

允许浏览器在一个 HTTP 请求正式发给服务器前预先执行一些操作,这包括 DNS 解析,TLS 协商,TCP 握手,这消除了往返延迟并为用户节省了时间。即对后续会访问的资源提前建立连接。

preconnect 可以直接添加到 HTML 中 link 标签的属性中,也可以写在 HTTP 头中或者通过 JavaScript 生成。

<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>

按照标准, 客户端会执行 DNS+TCP for HTTP, DNS+TCP+TLS for HTTPS origins的链接请求.

如下是为 Google Fonts 使用 preconnect 的例子,通过给 fonts.gstatic.com 加入 preconnect 提示,浏览器将立刻发起请求,和 CSS 请求并行执行。在这个场景下,preconnect 从关键路径中消除了三个 RTTs(Round-Trip Time)减少了超过半秒的延迟,lya Grigorik 的 eliminating RTTS with preconnect 一文中有更详细的分析。

preconnect

使用 preconnect 是个有效而且克制的资源优化方法,它不仅可以优化页面并且可以防止资源利用的浪费。

深入了解:https://www.keycdn.com/support/preconnect

参考链接

Preload, Prefetch And Priorities in Chrome

资源提示 —— 什么是 Preload,Prefetch 和 Preconnect?

Web预加载-Preload & Resource Hints

更多细节:使用 Proload/Prefetch 优化你的应用

附录:

W3C Preload:
草案: https://w3c.github.io/preload/
标准: https://www.w3.org/TR/preload/

W3C Resource Hints:
草案: https://w3c.github.io/resource-hints/
标准: https://www.w3.org/TR/resource-hints/