1、async & defer
- 区别
async异步加载脚本,加载完立马执行
defer异步加载脚本,并在DOMContentLoaded之前执行,若有多个,按照加载顺序执行脚本;async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的
- 兼容性
- 使用建议
1、defer更适合做异步加载,因为其考虑了脚本依赖,并在DOMContentLoaded之前执行;
2、async不考虑脚本依赖,加载完会立即执行,执行期间还会阻塞DOM解析,只适用不依赖任何脚本或不被任何脚本依赖的脚本;
3、浏览器遇到 <script>且没有defer或async属性的标签时,会触发页面渲染,因而如果前面CSS资源尚未加载完毕时,浏览器会等待它加载完毕再执行脚本,因此若js文件放头部,最好放css前面或加上defer/async
2、preload & dns-prefetch
(目前移动端支持度并不好,仅作参考)
DNS prefetching通过指定具体的URL来告知客户端未来会用到相关的资源,这样浏览器可以尽早的解析DNS。比如我们需要一个在example.com的图片或者视频文件。在<head>就可以这么写:
<link rel="dns-prefetch" href="//example.com">
项目中有用到第三方的代码时这么做尤其有益(其他的使用场景,比如当静态资源和HTML不在一个域上,而在CDN上;又比如在重定向前可以加上DNS prefetch)
3、资源阻塞及加载优先级
- 有3种原因会阻止页面加载资源,包括CSP、Mixed Content、Origin block,CSP是自己手动设置的一些限制,Mixed Content是https页面不允许加载http的内容,Origin Block主要是svg的href只能是同源的资源。
//只允许加载自己域的图片,否则报错
<meta http-equiv="Content-Security-Policy" content="img-src 'self';">
//将网页的http请求强制升级为https
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
//在https的网站请求http的内容就是Mixed Content,例如加载一个http的JS脚本,这种请求通常会被浏览器堵塞掉,有几种资源属于可选阻塞:audio,vedio,favicon,image即浏览器默认可以在https下加载http开头的这几种资源,但是当设置了以下meta时,所有http资源都无法在https下得到加载(image的srcset属性不算可选阻塞,src属性算)。而对于主动混合内容,如果用户设置允许加载也是可以加载的
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
//Origin Block主要是svg使用use获取svg资源的时候必须不能跨域
-
资源优先级
优先级
<!DOCType html>
<html>
<head>
<meta charset="utf-8">
<link rel="icon" href="4.png">
<img src="0.png">
<img src="1.png">
<link rel="stylesheet" href="1.css">
<link rel="stylesheet" href="2.css">
<link rel="stylesheet" href="3.css">
<link rel="stylesheet" href="4.css">
<link rel="stylesheet" href="5.css">
<link rel="stylesheet" href="6.css">
<link rel="stylesheet" href="7.css">
</head>
<body>
<p>hello</p>
<img src="2.png">
<img src="3.png">
<img src="4.png">
<img src="5.png">
<img src="6.png">
<img src="7.png">
<img src="8.png">
<img src="9.png">
<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<img src="3.png">
<script>
!function(){
let xhr = new XMLHttpRequest();
xhr.open("GET", "https://baidu.com");
xhr.send();
document.write("hi");
}();
</script>
<link rel="stylesheet" href="9.css">
</body>
</html>
这个html资源加载timeline如下:
解释1:
(1)每个域每次最多同时加载6个资源(http/1.1)
(2)CSS具有最高的优先级,最先加载,即使是放在最后面9.css也是比前面资源先开始加载
(3)JS比图片优先加载,即使出现得比图片晚
(4)只有等CSS都加载完了,才能加载其它的资源,即使这个时候没有达到6个的限制
(5)head里面的非高优化级的资源最多能先加载一张(0.png)
(6)xhr的资源虽然具有高优先级,但是由于它是排在3.js后面的,JS的执行是同步的,所以它排得比较靠后,如果把它排在1.js前面,那么它也会比图片先加载。
解释2:
(1)高优先级的资源(>=Medium)、同步请求和非http(s)的请求能够立刻加载
(2)只要有一个layout blocking的资源在加载,最多只能加载一个delayable的资源,这个就解释了为什么0.png能够先加载
(3)只有当layout blocking和high priority的资源加载完了,才能开始加载delayable的资源,这个就解释了为什么要等CSS加载完了才能加载其它的js/图片。
(4)同时加载的delayable资源同一个域只能有6个,同一个client即同一个页面最多只能有10个,否则要进行排队。
解释3:
白色条是指queue的时间段,而灰色的是已经in flight了但受到同域只能最多只能建立6个TCP连接等的影响而进入的stalled状态,绿色是TTFB(Time to First Byte)从开始建立TCP连接到收到第一个字节的时间,蓝色是下载的时间。
我们已经解释了大部分加载的特点的原因,对着上面那张图可以再重述一次:
(1)由于1.css到9.css这几个CSS文件是high priority或者是none delayable的,所以马上in flight,但是还受到了同一个域最多只能有6个的限制,所以6/7/9.css这三个进入stalled的状态
(2)1.css到5.css是layout-blocking的,所以最多只能再加载一个delayable的0.png,在它相邻的1.png就得排队了
(3)等到high priority和layout-blocking的资源7.css/9.css/1.js加载完了,就开始加载delayable的资源,主要是preload的js和图片