dns-prefetch、prefetch、prerender、preload浏览器预加载概述

本篇内容

  • DNS预处理
  • 资源预读取
  • 页面预渲染
  • 资源预加载

1 dns-prefetch(DNS预处理)

在很多网站如百度、淘宝的页面html中,我们都会看到类似如下的代码;

1
<link rel="dns-prefetch" href="//cms-bucket.nosdn.127.net">

那么问题来了,这里是什么意思呢?

这里就是本篇第一个内容:DNS预处理

1.1 DNS域名系统

要了解DNS预处理,那么首先得了解什么是DNS。DNS(Domain Name System,域名系统)用来确定域名对应IP的解析,当用户使用域名地址时,该系统就会自动把域名地址转为IP地址。

1.2 DNS预处理介绍

DNS预处理是一项使浏览器主动去执行域名解析的功能,其范围包括文档的所有链接,无论是图片的,CSS的,还是JavaScript等其他用户能够点击的URL。
DNS请求需要的带宽非常小,但是延迟却有点高,这点在手机网络上特别明显。预读取DNS能让延迟明显减少一些,例如用户点击链接时。在某些情况下,延迟能减少一秒钟。
在某些浏览器中,DNS预处理将会与页面实际内容并行发生。正因如此,某些高延迟的域名的解析过程才不会卡住资源的加载。

因此使用DNS预处理可以极大的加速(尤其是移动网络环境下)页面的加载,当你浏览网页时,浏览器会加载网页时对网页中的域名进行解析缓存。在某些图片较多的页面中,在发起图片加载请求之前预先把域名解析好将会有至少5%的图片加载速度提升。

所以当我们推断用户可能将访问某个域名下的网页或者图片时,便可以通过该技术优化后续页面的加载速度。

1.3 使用

X-DNS-Prefetch-Control头控制着浏览器的DNS预处理功能。

  • X-DNS-Prefetch-Control: on。(启用DNS预解析。在浏览器支持DNS预解析的特性时即使不使用该标签浏览器依然会进行预解析。)
  • X-DNS-Prefetch-Control: off。(关闭DNS预解析。这个属性在页面上的链接并不是由你控制的或是你根本不想向这些域名引导数据时是非常有用的。)

打开和关闭 DNS 预读取

你可以通过在服务器端发送X-DNS-Prefetch-Control报头,或是在文档中使用值为http-equiv的<meta>标签:

1
<meta http-equiv="x-dns-prefetch-control" content="on">

强制查询特定主机名

你可以通过使用rel属性值为link type中的dns-prefetch的<link>标签来对特定域名进行预读取(可以使用不完整的URL的主机名来标记预解析,但这些主机名前必需要有双斜线,相对协议)
如:

1
<link rel="dns-prefetch" href="//blog.michealwayne.cn">

强制对域名进行预处理在有的情况下很有用。比如,在网站的主页上,强制在整个网站上频繁引用的域名的预解析,即使它们不在主页本身上使用。即使主页的性能可能不受影响,这将提高整体站点性能。

1.4 兼容

– Safari: Safari5开始
– Chrome: All
– Firefox: Firefox3.5开始
– Opera: 未知
– IE: IE9开始(Pre-resolution)

caniuse-dns-prefetch compatibility

移动端的兼容ios和android都是未知,但总得来看兼容情况良好。

1.5 其他

需要注意,虽然dns-prefetch能够加快网页解析速度,但是也不能随便滥用,因为多页面重复DNS预解析会增加重复DNS查询的次数。

2 prefetch(资源预读取)

很多情况下,我们可以猜出用户很有可能接下来去查看一张图片或者其他资源,那么这时候能有什么优化的手段呢?

2.1 prefetch(资源预读取)介绍

资源预读取(链接预取)是一种浏览器机制,其利用浏览器空闲时间来下载或预取用户在不久的将来可能访问的文档。网页向浏览器提供一组预取提示,并在浏览器完成当前页面的加载后开始静默地拉取指定的文档并将其存储在缓存中。当用户访问其中一个预取文档时,便可以快速的从浏览器缓存中得到。

2.2 使用

浏览器会查找关系类型(rel)为next或prefetch的HTML<link> 或HTTP Link: header。下面是一个使用link标签的例子:

1
<link rel="prefetch" href="/images/big.jpeg">

同样效果的使用 HTTP Link: header 的例子:

1
Link: </images/big.jpeg>; rel=prefetch

Link: header 也可以通过使用 HTML meta 标签定义在 HTML 文档中:

1
<meta http-equiv="Link" content="</images/big.jpeg>; rel=prefetch">

rel=’prefetch’表示当所有资源都加载完后,开始预加载这里指定的资源,有最低的优先级

浏览器检查所有这些预取提示,并将每一个独立的请求排到队列之中,然后浏览器空闲时将对这些请求进行预取。每个页面都可以有多个预取提示,因为预取多个文档是合理的。例如,未来要访问的页面可能包含多张大图。

1
2
<link rel="prefetch alternate stylesheet" title="Designed for Mozilla" href="mozspecific.css">
<link rel="next" href="2.html">

使用js也可以实现预加载,如

1
2
3
4
5
6
7
8
9
10
11
12
var hint = document.createElement('link');
hint.setAttribute('rel', 'prefetch');
hint.setAttribute('href', 'next-page.html');
document.getElementsByTagName('head')[0].appendChild(hint);

// 改成方法
function addPrefetch(url) {
var hint = document.createElement('link');
hint.setAttribute('rel', 'prefetch');
hint.setAttribute('href', url);
document.getElementsByTagName('head')[0].appendChild(hint);
}

2.3 其他

  • https的页面里预加载http的资源会报错(浏览器的安全机制);
  • 只有带有关系类型为next或prefetch的<link>标签会被预拉取。
  • 资源正在被预载时点击了某个链接会发生什么?当用户点击一个连接,或开始任何形式的页面加载时,预取操作将被停止且任何预取提示将被丢弃。如果一个预取文档只下载了一部分,那么这部分文档将被保存在缓存中,供服务端发送一个 “Accept-Ranges: bytes” 的返回头。这个返回头通常是由网络服务器在返回静态内容时生成的。当用户真正访问这个已经(部分)预载过的文档时,该文档的剩余部分将被通过一个 HTTP byte-range 的请求获取。

注意:只有可缓存的资源才考虑使用预加载优化,否则浪费资源!;资源预读取的作用是通知浏览器加载下一页面可能会用到的资源,下一页面,下一页面!。

2.4 兼容

  • IE:IE11开始
  • Firefox:all
  • Chrome:Chrome8开始
  • Safari:不支持
  • Opera:Opera15开始

caniuse

看上去移动端安卓基本支持,而ios至今都不支持

3 prerender(资源预渲染)

dns-prefetch和prefetch实现了dns和资源文件的预加载,那么是否能直接渲染出下一个要点击的页面呢?

3.1 prerender(资源预渲染)介绍

资源预读取(链接预取)是一种浏览器机制,其利用浏览器空闲时间来下载或预取用户在不久的将来可能访问的页面。

3.2 使用

1
<link rel='prerender' href='http://www.michealwayne.cn'>

rel=’prerender’ 表示浏览器会帮我们渲染但隐藏指定的页面,一旦我们访问这个页面,则秒开了!

在Firefox中或用 rel=’next’ 来声明

1
<link rel='next' href='http://www.michealwayne.cn'>

3.3 兼容

  • IE:IE11
  • Firefox:不支持
  • Chrome:Chrome13开始
  • Safari:不支持
  • Opera:Opera15开始

caniuse

看上去移动端至今都不支持

4. preload(资源预加载)

之前所说的dns-prefetch、resources-prefetch、prerender都是为下一页面做准备,那么有什么方法可以为当前页面即将加载的资源做准备呢?

4.1 preload(资源预加载)介绍

资源预加载能够让你在你的HTML页面中 <head>元素内部书写一些声明式的资源获取请求,可以指明哪些资源是在页面加载完成后即刻需要的。对于这种即刻需要的资源,你可能希望在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。

4.2 使用

我们将使用preload作为rel属性的属性值。这种做法将把<link>元素塞入一个预加载器中,这个预加载器也将用于其他我们所需要的,各种各样的,任意类型的资源。为了完成基本的配置,你还需要通过href和as属性指定需要被预加载资源的资源路径及其类型。

1
2
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">

在这里,我们预加载了CSS和JavaScript文件,所以在随后的页面渲染中,一旦需要使用它们,它们就会立即可用。

其中as属性的值可以为

  • “script”
  • “style”
  • “image”
  • “media”
  • “document”

onload事件

可以定义资源加载完毕后的回调函数。

1
<link rel="preload" href="..." as="..." onload="preloadFinished()">

4.3 其他

preload还有许多其他好处。使用as来指定将要预加载的内容的类型,将使得浏览器能够:- 更精确地优化资源加载优先级。

  • 匹配未来的加载需求,在适当的情况下,重复利用同一资源。
  • 为资源应用正确的内容安全策略。
  • 为资源设置正确的Accept请求头。

不是所有的资源都可以预加载。当资源为以下列表中的资源时,将阻止预渲染操作:

  • 1.URL 中包含下载资源
  • 2.页面中包含音频、视频
  • 3.POST、PUT 和 DELETE 操作的 ajax 请求
  • 4.HTTP 认证(Authentication)
  • 5.HTTPS 页面
  • 6.含恶意软件的页面
  • 7.弹窗页面
  • 8.占用资源很多的页面
  • 9.打开了 chrome developer tools 开发工具

注意:preload不会阻塞windows的onload事件。

4.4 兼容

  • IE:不支持
  • Firefox:Firefox59开始
  • Chrome:Chrome50开始
  • Safari:Safari11.1开始
  • Opera:Opera37开始

caniuse

ios11.3开始支持、安卓5.6开始支持

5 动态预加载

以preload为例,使用js也可以实现预加载,如

1
2
3
4
5
6
7
8
9
10
11
12
var hint = document.createElement('link');
hint.setAttribute('rel', 'prefetch');
hint.setAttribute('href', 'next-page.jpg');
document.head.appendChild(hint);

// 改成方法
function addPrefetch(url) {
var hint = document.createElement('link');
hint.setAttribute('rel', 'prefetch');
hint.setAttribute('href', url);
document.head.appendChild(hint);
}

6 对比

名称 作用页面 作用文件 兼容情况
dns-prefetch 后续页面 基本兼容
prefetch 后续页面 document、media、image、style、script Chrome及安卓支持情况良好,Safari及ios至今不支持
prerender 后续页面 页面及其相关资源 pc兼容较好,移动端及Safari不支持
preload 当前页面 document、media、image、style、script pc、移动端最新本基本支持,IE不支持

其他还有如preconnect以及subsource等预处理方式本篇不做介绍。

参考资料