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" >
項目中有用到第三方的代碼時這么做尤其有益(其他的使用場景,比如當靜態資源和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和圖片