Script標簽是我們常用的引用js腳本的一種方式。
擼代碼的時候,我們常常只寫src屬性,直接忽略其他屬性。
最近發現了2個可以利用的屬性:async、defer。
顧名思義async就是異步,在不影響其他資源加載的同時,異步加載這個文件;defer就是延遲加載。
下面是高三上的解釋:
Async: 可選屬性。表示應該立即下載腳本,但不應妨礙頁面中的其他操作,比如下載其他資源或等待加載其他腳本。只對外部腳本文件有效(寫在html文件中的js代碼,添加此屬性無效,仍按代碼加載順序執行)。 |
Defer: 可選屬性。標識腳本可以延遲到文檔完全被解析和顯示之后再執行。只對外部腳本文件有效。 |
是否真的如上所述,下面我們用個demo來驗證一下。
Html代碼:
進入的js文件中,同文件序號分別console.log,1,2,3,4,5,6;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>test1 test2</h1>
</body>
<script defer> console.log(0) </script>
<script src='js1.js'></script>
<script src='js2.js'></script>
<script src='js3.js'></script>
<script src='js4.js'></script>
<script src='js5.js'></script>
<script src='js6.js'></script>
</html>
在瀏覽器中打開這個html文件,我們可以看到6個js文件按照順序加載。
Ok.現在我給js1文件加上defer屬性,看看。
<script defer src='js1.js'></script>
實驗證明:
js文件依然按照書寫順序加載。
但是在控制台可以看到,js1文件的代碼是最后執行的
那我們還原代碼,給js6文件加上async屬性試試,看看會不會第一個輸出6
<script async src='js6.js'></script>
很遺憾,實時並沒有按照預想的那樣輸出6,0,1,2,3,4,5
如上圖代碼還是按照順序執行了,為什么defer生效了,async沒生效呢?
我們換個文件試試,給中間位置的某個文件添加async屬性。我給js3加了async屬性后,代碼執行順序發生了如下變化:
那么問題又來了,為什么不是想象中的那個順序:3,0,1,2,4,5,6
下面我們來分析一下原因
1,為什么async屬性加到最后一個script標簽中無效?
2,為什么添加了async屬性的代碼不是優先執行的?
我們都知道,js是按照書寫順序加載,按照書寫順序執行的。文件加載之后,程序便開始解析文件中的代碼。
因此添加了async屬性的文件,需要加載到這個文件位置的時候才會生效,js6已經是最后一個文件了,最后一個加載的文件中的代碼自然就最后執行,因此看起來async在我們的第一個demo中沒有生效。
Async是異步加載,而不是優先加載,因此js3文件添加了async屬性后,當文件加載到js3,同時開始加載js3之后的文件,於是便出現了上圖0,1,2,4,3,5,6的結果,當然這個結果不是必然的,因為我們的demo里面的代碼非常簡短,如果js4中的代碼邏輯復雜,那么結果可能任然是0,1,2,3,4,5,6。
說到這里,大家明白async和defer的原理了嗎?
那么什么場景下可以用到這些屬性呢?
比如有些第三方庫,要求在header中引入(這就意味着第三方插件庫會優先加載),但是我們並不需要在頁面加載之初就用到這個插件。那么我們可以加上defer屬性使之最后加載。同理,如果頁面加載的同時需要用到第三方插件,那么我們引用的時候可以加async屬性,這樣網站內的資源就可以與插件資源異步加載。這中方法會給網站其他資源的加載節省出一些時間,不失為一種頁面優化的方法。
參考資料:
JavaScript高級程序設計(第3版)