默認(rèn)情況下,瀏覽器是同步加載 JavaScript 腳本寝贡,即渲染引擎遇到<script>標(biāo)簽就會停下來扒披,等到執(zhí)行完腳本,再繼續(xù)向下渲染兔甘。如果是外部腳本谎碍,還必須加入腳本下載的時間。
如果腳本體積很大洞焙,下載和執(zhí)行的時間就會很長蟆淀,因此造成瀏覽器堵塞,用戶會感覺到瀏覽器“卡死”了澡匪,沒有任何響應(yīng)熔任。這顯然是很不好的體驗,所以瀏覽器允許腳本異步加載唁情,下面就是兩種異步加載的語法疑苔。
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
上面代碼中,<script>標(biāo)簽打開defer或async屬性甸鸟,腳本就會異步加載惦费。渲染引擎遇到這一行命令兵迅,就會開始下載外部腳本,但不會等它下載和執(zhí)行薪贫,而是直接執(zhí)行后面的命令恍箭。
defer
與async
的區(qū)別是:defer
要等到整個頁面在內(nèi)存中正常渲染結(jié)束(DOM 結(jié)構(gòu)完全生成,以及其他腳本執(zhí)行完成)瞧省,才會執(zhí)行扯夭;async
一旦下載完,渲染引擎就會中斷渲染鞍匾,執(zhí)行這個腳本以后交洗,再繼續(xù)渲染。一句話橡淑,defer
是“渲染完再執(zhí)行”构拳,async
是“下載完就執(zhí)行”。另外梳码,如果有多個defer
腳本隐圾,會按照它們在頁面出現(xiàn)的順序加載,而多個async
腳本是不能保證加載順序的掰茶。
只有一個腳本的情況
沒有defer
或async
屬性,瀏覽器會立即下載并執(zhí)行相應(yīng)的腳本蜜笤,并且在下載和執(zhí)行時頁面的處理會停止濒蒋。
<script src="example.js"></script>
有了defer
屬性,瀏覽器會立即下載相應(yīng)的腳本把兔,在下載的過程中頁面的處理不會停止沪伙,等到文檔解析完成后腳本才會執(zhí)行。
<script defer src="example.js"></script>
有了async
屬性县好,瀏覽器會立即下載相應(yīng)的腳本围橡,在下載的過程中頁面的處理不會停止,下載完成后立即執(zhí)行缕贡,執(zhí)行過程中頁面處理會停止翁授。
<script async src="example.js"></script>
如果同時指定了兩個屬性,則會遵從async
屬性而忽略defer
屬性晾咪。
<script async src="example.js" defer async></script>
下圖可以直觀的看出三者之間的區(qū)別:
其中藍(lán)色代表js腳本網(wǎng)絡(luò)下載時間收擦,紅色代表js腳本執(zhí)行,綠色代表html解析谍倦。
多個腳本的情況
兩個腳本都沒有defer
或async
屬性塞赂,瀏覽器會立即下載并執(zhí)行腳本example1.js,在example1.js腳本執(zhí)行完成后才會下載并執(zhí)行腳本example2.js昼蛀,在腳本下載和執(zhí)行時頁面的處理會停止宴猾。
<script src="example1.js"></script>
<script src="example2.js"></script>
有了defer
屬性圆存,瀏覽器會立即下載相應(yīng)的腳本example1.js
和example2.js
,在下載的過程中頁面的處理不會停止仇哆,等到文檔解析完成才會執(zhí)行這兩個腳本沦辙。
HTML5規(guī)范要求腳本按照它們出現(xiàn)的先后順序執(zhí)行,因此第一個延遲腳本會先于第二個延遲腳本執(zhí)行税产,而這兩個腳本會先于DOMContentLoaded
事件執(zhí)行怕轿。
在現(xiàn)實當(dāng)中,延遲腳本并不一定會按照順序執(zhí)行辟拷,也不一定會在DOMContentLoaded
事件觸發(fā)前執(zhí)行撞羽,因此最好只包含一個延遲腳本。
<script defer src="example1.js"></script>
<script defer src="example2.js"></script>
有了async
屬性衫冻,瀏覽器會立即下載相應(yīng)的腳本example1.js和example2.js诀紊,在下載的過程中頁面的處理不會停止,example1.js和example2.js哪個先下載完成哪個就立即執(zhí)行隅俘,執(zhí)行過程中頁面處理會停止邻奠,但是其他腳本的下載不會停止。標(biāo)記為async
的腳本并不保證按照制定它們的先后順序執(zhí)行为居。異步腳本一定會在頁面的load事件前執(zhí)行碌宴,但可能會在DOMContentLoaded
事件觸發(fā)之前或之后執(zhí)行。
<script async src="example1.js"></script>
<script async src="example2.js"></script>
小結(jié)
將腳本放在 </body>
前面就可以了蒙畴,如果有依賴的則按照順序放好贰镣。如果一定要放在head
標(biāo)簽里面,最好是加defer
屬性膳凝。