1.沒有defer
或async
瀏覽器遇到指令碼的時候會暫停渲染並立即載入執行指令碼(外部指令碼),“立即”指的是在渲染該 script 標籤之下的文件元素之前,也就是說不等待後續載入的文件元素,讀到就載入並執行。因此如果將JS指令碼放置在head的話會產生阻塞
,並且指令碼當中對於DOM的操作也會出現報錯,因為還沒有生成。
放在body底部的JS指令碼的執行順序是按照在文件中的先後順序執行的,而不是按照下載下的順序
2.有async
過程如下:
1.瀏覽器開始解析網頁
2.解析過程中,發現帶有async屬性的script標籤
3.瀏覽器繼續往下解析 HTML 網頁,同時並行下載外部指令碼
4.指令碼下載完成,瀏覽器暫停解析網頁,開始執行下載的指令碼
5.指令碼執行完畢,瀏覽器恢復解析網頁
async
指令碼執行順序是下載的順序
3.有defer
過程如下:
1.瀏覽器開始解析網頁
2.解析過程中,發現帶有defer屬性的指令碼元素
3.瀏覽器繼續往下解析網頁,同時並行下載指令碼元素載入的外部指令碼
4.瀏覽器完成解析網頁,此時再回過頭執行已經下載完成的指令碼
defer
指令碼執行順序是出現的先後順序
4.defer
還是async
?
兩者之間的選擇則是看指令碼之間是否有依賴關係,有依賴的話應當要保證執行順序,應當使用defer
沒有依賴的話使用async
,同時使用的話defer
失效。要注意的是兩者都不應該使用document.write
,這個導致整個頁面被清除。
瀏覽器完整過程是先解析渲染HTML,當遇到指令碼檔案的時候則執行指令碼檔案,等待指令碼檔案執行完畢才繼續解析html,因此會產生阻塞頁面的情況,因此最好將指令碼放在body底部,當瀏覽器遇到標有defer的時候則會下載該指令碼,同是繼續解析html,然後等到dom解析完畢之後才解析defer指令碼,而如果遇到async指令碼的時候同樣是下載該指令碼同是繼續解析html,當anync下載完畢之後,而html尚未解析完畢,也會先解析async指令碼,等待async指令碼解析完畢之後才繼續解析html。
詳細的過程對比參考下圖: