likes
comments
collection
share

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

作者站长头像
站长
· 阅读数 5

如果将async defer prefetch preload @import link:media dns-prefetch称之为对html文件的配置,那么这些配置对于初学者来说很难理解的,本文分为上下两个部分对这些概念进行分析,力求做到简单易懂。

4.7 测试7:使用preload利用空闲时间加载资源

首先这个“利用空闲”就已经明白的说出了这种做法是不阻塞的!

将index.html修改成如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="preload" href="http://localhost:3000/fast" as="script">
</head>
<body>
    <h1>我出现了!</h1>
    <button id="btn">点我翻页</button>
    <script>
        const btn = document.getElementById('btn');
        const o = document.createElement('script');
        o.src = "http://localhost:3000/fast";
        btn.addEventListener('click', ()=>{
            document.body.append(o);
        })
    </script>
</body>
</html>

需要注意的事情是:link中的as="script"一定要写,否则的话就不会起到任何作用!

在点击按钮之前,控制台中不会打印任何内容,网络面板所示为:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

注意这里的优先级是:

而在点击了按钮之后立马打印出fast

此时网络面板中并没有任何变化!

对比prefetch,可以发现,prefetch不一定要写as但是preload一定需要!

此外注意fast资源的图标,在prefetch加载完资源之后是空白的,而preload是由icon的,这就是为什么它非要指定资源的类型了;并且preload完成之后其响应和预览中是有值的。

4.8 测试8:验证浏览器请求css资源是采用并发的方式

请求两个css,名字分别为2.css和3.css,表示它们的耗时分别为2s和3s。 touch 2.css 3.css

:root{
    color:pink;
}

:root{
    background-color:pink;
}

然后修改后端服务器,增加两条路由,如下所示:

app.get('/2',(req,res)=>{
    res.setHeader('Connection', 'close');
    setTimeout( () => {
        const fileContent = fs.readFileSync(path.join(__dirname, './2.css'));
        res.end(fileContent);  
    } , 2000)
})

app.get('/3',(req,res)=>{
    res.setHeader('Connection', 'close');
    setTimeout( () => {
        const fileContent = fs.readFileSync(path.join(__dirname, './3.css'));
        res.end(fileContent);  
    } , 3000)
})

然后修改index.html中的内容如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/2">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/3">
</head>
<body>
    <h1>我出现了!</h1>
</body>
</html>

打开index.html发现:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

而对应的:

完成用时:3.02 秒

DOMContentLoaded:3.02 秒

加载时间:3.02 秒

所以起码在这个时候请求css是并发的。

接下来展示一下使用@import的不好之处:

修改3.css为:

@import url('http://localhost:3000/2');

:root{
    background-color:pink;
}

修改index.html中的内容为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/3">
</head>
<body>
    <h1>我出现了!</h1>
</body>
</html>

此时打开index.html,网络面板中的显示内容为:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

完成用时:5.02 秒

DOMContentLoaded:5.02 秒

加载时间:5.02 秒

也就是说并行变成了串行,这肯定是有问题的!所以@import不被使用的原因也就在此了!

4.9 测试9:浏览器并发数目确定

修改index.html的内容为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/2">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/3">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/4">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/5">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/6">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/7">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/8">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/9">
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/10">
</head>
<body>
    <h1>我出现了!</h1>
</body>
</html>

然后在后端增加相应的路由

也不必增加对应的css文件了,让这些不同的路由指向相同的css文件也是可以的!

打开index.html发现:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

也就是说排队的有三个,所以此时最大的并发请求数目为6个!

4.10 测试10:css的懒加载,使用media字段

在使用link加载css文件的时候,使用media字段来实现具体情景下才加载css的效果,将index.html改写为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="http://localhost:3000/3" media="(max-width:40em)">
</head>
<body>
    <h1>我出现了!</h1>
</body>
</html>

将浏览器最大化,然后访问index.html,网络面板如图所示:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

完成用时:3.04 秒

DOMContentLoaded:40 毫秒

加载时间:3.04 秒

然后将浏览器最小化,再访问index.html:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

居然是最高!

完成用时:3.03 秒

DOMContentLoaded:3.01 秒

加载时间:3.02 秒

于是得出结论:使用了media字段之后的link标签可以根据media所设定的条件来改变此资源的优先级,以及是否阻塞DOM的渲染!

不仅如此,media字段还会让浏览器在宽度大于40em和小于40em的时候表现出不同的样式!拖拽改变窗口的大小就能够看到这种变化了!

4.11 测试11:dns预加载

首先要知道本机的hosts文件在哪里,这样的话就可以捏造一个域名,强行开启dns解析:hosts文件的位置在C:\Windows\System32\drivers\etc,打开这个文件,并在最后一行追加:

127.0.0.1       supx

然后以管理员身份保存此文件。

接下来访问http://supx:8800看能否成功,成功的话则说明已经配置成功了。

然后就是如何清除dns缓存,清除了才能够让浏览器每一次都发起dns解析:

正确的做法是:ctrl+shift+delete清除缓存,然后ctrl+shift+R强制刷新页面,这样就可以将浏览器缓存的dns清除了。

然后改变index.html文件内容如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="http://localh<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <link rel="stylesheet" type="text/css" href="http://supcon:3000/3" media="(max-width:40em)"> -->
    <link rel="dns-prefetch" href="http://supcon">
</head>
<body>
    <h1>我出现了!</h1>
    <button id="btn">点我添加样式</button>
    <script>
        const btn = document.getElementById('btn');
        const lk = document.createElement('link');
        lk.rel = "stylesheet";
        lk.type = "text/css";
        lk.href = "http://supcon:3000/3";
        lk.media = "(max-width:40em)";
        btn.addEventListener('click', ()=>{
            document.head.append(lk);
        })
    </script>
</body>
</html>
<body>
    <h1>我出现了!</h1>
</body>
</html>

打开index.html然后等待一秒,点击按钮,网络面板上的信息如下:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

可以看到dns解析过程只占用了5微秒;

然后删除dns预解析: <link rel="dns-prefetch" href="http://supcon">

清除dns缓存之后,做相同的操作,效果为:

一文解决async defer prefetch preload @import link:media dns-prefetch (下)

这时不要被它的比例迷惑了,这次整整用了61毫秒!

所以dns-prefetch显然是有效的!但是这5微秒也说明了,即使使用dns-prefetch在这个事情上还是要花费时间的。