script 的三種載入模式:預設載入、defer、async

大家好,我是前端西瓜哥。今天我們來了解一下 script 指令碼的三種載入方式。

script 的三種載入模式:預設載入、defer、async

預設載入

一般的 script 寫法為:

這種寫法有一個問題:它會

阻塞 HTML 的 DOM 構建

假如我們在 head 元素中使用了 script 指令碼,它就會阻止後面元素的渲染,包括 body 元素,此時執行

document。querySeletor(‘body’)

拿到的是 null。

<!DOCTYPE html> Document

此外,當指令碼足夠大,載入執行足夠久時,會導致頁面長時間沒能渲染出完整頁面。

這也是我們將業務程式碼指令碼放到 body 最下邊的原因,這樣能確保指令碼能夠訪問一個完整的 DOM 樹,也不會阻止頁面的渲染。

缺點是,HTML 很長的時候,解析到指令碼就會花上一點時間,然後才會請求對應的指令碼資源。

不過通常來說,HTML 內容都比較簡單,二者感受不到太大區別,除非你網很卡。

defer 載入

defer,“延遲” 之意。這裡的延遲,指的是延遲執行指令碼,下載則不會被阻塞。

需要注意的是,

defer 屬性對內嵌指令碼無效

。畢竟指令碼內容就在 HTML 裡了,完全不需要請求資源了好吧。

給 script 標籤添加了 defer 屬性後,指令碼不會阻塞 DOM 樹的構建,會先下載資源,然後等待到在 DOMContentLoaded 事件前執行。

DOMContentLoaded 事件的觸發時機為初始 HTML 被構建完成時,此時 CSS、圖片等資源不需要載入完,但我們的指令碼要執行完。

如果多個 script 設定了 defer 屬性,這幾個 script 的執行順序和宣告順序相同,即最前面的指令碼先執行

。並不是誰先下載誰先執行。

實際開發中,我們可以將業務程式碼指令碼加上 defer 屬性,放到更上層的 head 標籤下。

這也是最新版 HtmlWebpackPlugin 外掛的預設引入打包指令碼的方式。

async 載入

async,“非同步” 之意。同樣對內嵌指令碼無效。

設定 async 後,指令碼一旦被下載好了就會執行,不管什麼時機。

適合與執行順序無關的指令碼,比如廣告、網站流量分析指令碼。

比如插入 Google 分析指令碼:

動態載入

還有一種用指令碼載入指令碼的特殊情況,這裡也說一說。

腳本里建立一個 script 元素,設定好 src,然後載入到 DOM 樹上,接著指令碼就會下載和執行了。

建立的 script 元素預設會給 async 設定為 true,即一旦下載好就立即執行。

如果你要載入有依賴關係的多個指令碼,就需要將 async 設定為 false。

這樣寫,就能保證先執行 app-a。js,再執行 app-b。js

它無法做到比 HTML 中其他非動態載入的 script 指令碼更早執行

,這點需要注意。

結尾

script 有三種常見載入模式:

預設載入:會阻塞 DOM 構建

defer 載入:下載照舊,但執行延後

async:下載完就立即執行,適合沒有依賴的指令碼

此外還有動態載入的指令碼的情況,這種指令碼預設為 async 載入形式,可透過將 async 屬性設定為 false 來解除,讓指令碼順序執行。

我是前端西瓜哥,歡迎關注我。