Resouce Hints 让我们可以帮助浏览器寻找到它将要用到的资源,然后提前下载它们以期获得更佳的性能。
对于现代化的网站,速度优化需要的不再仅仅是最小化初始下载大小和 critical rendering path ,我们还可以通过尽早地解析并预取资源来优化资源的加载。
“预取”只是在一个资源被需要之前就开始下载的行为,以期来提供快速、即时的体验。
Dns-prefetch
Dns-prefetch 是在浏览器请求资源之前,开启资源所在的每个域的 DNS 解析的过程,目的是当浏览器真正地请求资源时节省 DNS 解析时间。
你可以把 DNS 解析理解成浏览器为了将
domain/hostname
转化成一个访问资源所需 ip 地址的必经过程(这个过程就是把对用户友好的 url,比如 www.medium.com/,转成 http://80.72.139.1.0)。
通过检查 amazon.com 站点的源码,你会在其主页的顶部找到以下代码:
<link rel='dns-prefetch' href='//g-ecx.images-amazon.com'>
<link rel='dns-prefetch' href='//completion.amazon.com'>
复制代码
Amazon.com 使用 DNS-prefetch 来解析多个域名,从中获取不同的资源,如图像、JS 和 CSS 文件。当浏览器遇到这些 URLs 时,它首先检查缓存,如果没有命中缓存,则向 DNS 服务器发送请求来解析出域名相应的 IP 地址。这些请求在后台处理并不会阻塞页面的渲染。
DNS 查询的成本是很低的——它们只通过网络发送几百个字节,因此没有太大的风险。
你可以在这个网站检查浏览器是否支持 DNS-prefetch:caniuse.com/#feat=link-…
Preconnect
如果你使用的是 HTTPS,它可以完成与某个域建立连接的所有工作,包括 DNS 查找、TCP 握手和TSL 协商。
preconnect 可以通过 提前执行这项工作来屏蔽高延迟连接 以及削减启动请求的宝贵时间:
<link rel="preconnect" href="//example.com">
复制代码
你可以在这个网站检查浏览器是否支持此功能:caniuse.com/#feat=link-…
Prefetch
摘自 MDN:
Link prefetching 是一种浏览器机制,这种机制利用浏览器的空闲时间来下载或者预取用户可能在不久的将来访问的文档。一个 web 页面向浏览器提供一组 prefetching hints,然后浏览器加载完页面后,开始静默地预取指定文档并将其存储在缓存中。当用户访问其中一个预取文档时,可以快速地将其从浏览器的缓存中提取出来。
因此,这意味着 prefetch 用于获取和缓存资源,这些资源将在用户可能访问的后续路由中使用。
prefetch 可以用于一个带有 prefetch
和 url
属性的 link
标签:
<link rel="prefetch" href="//example.com/next-page.html" as="html" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">
复制代码
as
属性是可选的,它用来帮助浏览器的 preloader 优化预取过程。
crossorigin
属性也是可选的,它允许你为给定的资源指定跨源策略。
只有能够被缓存的元素应该使用预取功能。
你可以在这个网站检查浏览器是否支持此功能:caniuse.com/#feat=link-…
Preload
preload 类似于 prefetch,区别在于 prefetch 用于发起对后续路由中将要使用的资源的请求,而 preload 则用于预取同一个页面中将要用到的资源。
<link rel="preload" href="/library.js" as="script">
复制代码
prefetch 是一个可选的、低优先级的用于获取在后续的导航中可能用到的一个资源的 fetc;preload 是一个强制的、高优先级的用于获取当前导航必需资源的 fetch。
如果你使用了懒加载来加速页面的加载,或者在 JavaScript 或 CSS 内部告诉了浏览器存在的资源,比如 web 字体,那么 preload 将非常有用。
这还有一个有趣的用例,你可以对预加载的资源进行更细粒度的控制:
<script>
function preloadFinished(e) { ... }
function preloadError(e) { ... }
</script>
<!-- listen for load and error events -->
<link rel="preload" href="app.js" as="script" onload="preloadFinished()" onerror="preloadError()">
复制代码
你可以在这个网站查看浏览器的支持情况:caniuse.com/#feat=link-…
从 Safari Technology Preview 13 版本也开始提供这个功能了:developer.apple.com/safari/tech…
Prerender
预渲染是一种告诉浏览器预取并执行给定资源的方法。
你可以通过插入 rel
为 prerender
的 link
元素来触发预渲染,例如:
<link rel='prerender' href='//pagetoprerender/landing.html'>
复制代码
你可以将预渲染视为在新选项卡中加载页面,只是该选项卡对用户隐藏,直到用户发出请求时才呈现。
由于浏览器会执行预渲染页面上的所有脚本,因此你可能会遇到一些意外的后果,比如触发 analytics beacons,而实际上页面并没有被展示。你可以使用 Page Visibility API 来解决这些问题。
你应该理性地使用 prerender,因为它可能会导致带宽和 CPU 使用的上升。你应该只在这种情况下考虑使用 prerender,那就是如果你对用户将要使用某个资源高度自信,并且你确实提供了附加的价值。
请注意,是否启动预渲染的决定权在于浏览器,它可以基于一组 预定义规则 选择不启动或放弃预渲染功能。
你可以在此查看浏览器的支持情况:caniuse.com/#feat=link-…
Hint probability
Hint probability 是一个 link
的元素的 pr
属性,可用于指示给定资源是否必要的概率,并且你可以将其与任何上面提到的资源提示一起使用,但是 preload 除外。
// The pr attribute expects a float value in the [0.0-1.0] range
<link rel="prefetch" href="//example.com/next-page.html" pr="0.75">
复制代码
这个 hint 用于帮助浏览器决定一个给定 hint 的执行。在设备中资源受限的情况下,浏览器可以决定仅执行高可用性提示。
在运行时注入resource hints
上面提到的每个 resource hint 都可以在运行时使用 JavaScript 触发,你只需要使用正确的属性创建 link
元素并将其添加到页面的 head
标签中。
var hint =document.createElement("link")
hint.setAttribute(“rel”,”prerender”)
hint.setAttribute(“href”,”next-page.html”)
document.getElementsByTagName(“head”)[0].appendChild(hint)
复制代码
分析架构模式、研究用户行为,然后迭代产品
对你的架构进行分析,找出可以从中获取最大收益的地方:
- 每个页面上哪个才是最重要的资源?
- 哪些操作会触发下载其他内容?
- 哪些 assets 是在 critical rendering path 上?
研究用户在你网站上的行为:
- 访问次数最多的页面是哪些?
- 用户转化的过程是什么?
- 某项操作的频次是多少?
始终使用 webpagetest 等工具在更改前后进行速度测量。
能力越大,责任越大。