dns-prefetch DNS 预解析优化页面加载速度

发表于2017-01-09   1643次阅读

浏览器访问一个链接时并不是直接将请求到网页对应的服务器上,而是先要做域名解析——将域名解析到网页对应的服务器 ip 地址,然后浏览器才能和服务器之间建立起通信交互,其过程大致如下图所示:

做域名解析就要访问域名服务器(在没有缓存缓存的情况下),这就会出现网路开销,开销的大小新取决于你的 dns 服务器和你的距离,一般要要几十毫秒到几百毫秒之间,请求的域名比较少的时候可能对用户来说无感知,单请求的域名多了,尤其是请求之间有先后顺序,那延迟就比较明显了。一般的大型网站,资源都是分开存储的,一个页面上请求十几个域名是常有的事情。好在浏览器比较聪明,会把 dns 解析结果缓存一段时间(谷歌浏览器可以通过 chrome://net-internals/#dns 查看浏览器缓存的 dns 解析结果),以减少相同域名的再次解析。但用户第一次访问你的页面,或者长时间没有访问你的页面,都会重新请求 dns 服务器来解析域名。

dns-prefetch(dns 预解析)指令可以在尚未访问 url 的时候提前做 dns 解析(和其他 url 请求并行执行),从而在真正请求 url 的时候避免对 dns 服务器的解析,进而达到加速网页加载的目的。

在 Chrome 中默认已经开启对静态资源的 dns 预解析,因为页面下载到浏览器时已经知道需要访问哪些静态资源 url,所以浏览器会提前做 dns 预解析操作。但对于通过 js 动态加载的 url,浏览器就不会自动预解析了,这时 dns-prefetch 就会派上明显的用场。我们举一个例子,看下真实的效果:


function load(tag, url) {
    var node = document.createElement(tag);
    if ('link' == tag) {
        node.type = "text/css"; 
        node.rel = "stylesheet"; 
        node.href = url;
    } else {
        node.src = url;
    }
    document.body.append(node);
}

setTimeout(function(){
    load('link', '//cdn.bootcss.com/bootstrap/4.0.0-alpha.5/css/bootstrap-flex.min.css');
    load('script', '//cdn.bootcss.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js');

    load('link', '//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css');
    load('script', '//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js');

    load('link', '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css');
    load('script', '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js');

    load('link', '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css');
    load('script', '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/js/bootstrap.min.js');
}, 2000);

使用 dns-prefetch 的代码:

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta http-equiv="x-dns-prefetch-control" content="off">
    </head>
    <body>
        <script src="dynamic_load_res.js"></script>
    </body>
</html>

x-dns-prefetch-control 表示手动关闭 dns-prefetch 功能。

我们通过 http://www.webpagetest.org/ 的测试截图如下:

使用 dns-prefetch 的代码(不要忘记加 //):

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <link rel="dns-prefetch" href="//cdn.bootcss.com">
        <link rel="dns-prefetch" href="//netdna.bootstrapcdn.com">
        <link rel="dns-prefetch" href="//maxcdn.bootstrapcdn.com">
        <link rel="dns-prefetch" href="//cdnjs.cloudflare.com">
    </head>
    <body>
        <script src="dynamic_load_res.js"></script>
    </body>
</html>

效果截图如下:

从图中可见,dns 解析大幅提前到加载资源之前了。真正加载资源文件时就不用再次请求 dns 服务器了。