普通 script 標籤
- JS 可能會修改 HTML 和 CSS,所以 JS 的下載執行過程不能和 HTML / CSS 並行
- HTML 解析過程當中若碰到外聯的 JS,會暫時停止 HTML 的解析流程,等候腳本下載和解析完成後再繼續進行以前中斷掉的 HTML 解析流程
- 這樣就致使了 script 標籤外聯 JS 加載有這樣的缺點:會影響整個頁面效率,一旦網速很差整個網站將等待 JS 加載而不進行後續渲染,因爲中斷了 HTML 解析流程,因此致使頁面空白,影響體驗
- 之前的寫法是將 script 標籤寫在 body 最後面,等 DOM 所有解析完成後才加載 JS,HTML5 標準有另外一套異步加載 JS 的方法
defer
- 在 script 標籤的行間寫一個
defer=「defer」
或直接寫 defer
就可讓這個 script 外聯的 JS 變成異步加載了
- HTML 解析流程中若碰到外聯 JS,會開闢新線程來下載腳本,下載完成後不會當即解析,不會阻塞 HTML 的解析流,等到 HTML 解析完畢後(不包括下載完裏面的資源),再進行腳本的執行解析
- 該方法只有 IE 和一些高版本的 firefox 和 chrome 能夠用
- 這種方式能夠在 script 標籤裏面寫代碼
- 注意:IE6 和 IE7 的異步加載最多隻能有 2 個,超過兩個時必須等前兩個加載完纔會加載第三個
- 全部 defer 的 JS 代碼都保證按照順序執行
async
- async 是 asynchronous 的縮寫,是 HTML5 標準,
- HTML 解析流程中若碰到外聯 JS,會開闢新線程來下載腳本,下載完成後當即解析執行,且解析流程會中斷 HTML 解析流程,等到腳本執行完成後纔會繼續進行以前中斷掉的 HTML 解析流程
- 這種方法除了 IE6 ~ IE8 其餘的瀏覽器都好用
- 該方式不能把代碼寫在 script 標籤裏,只能引用外部腳本(雖然標準是這麼寫的,但如今隨着內核升級 async 的 script 標籤裏也能夠寫代碼,在沒有 src 狀況下)
- async 的 JS 代碼不能保證是順序執行的,按照 race 的方式哪一個腳本先下載完就先解析哪一個腳本
- defer 和 async 這兩個屬性不能一塊兒使用
兼容性寫法
- 直接寫兩個 script 標籤,一個是 defer 一個是 async,這種方法有缺陷,IE 高版本會加載兩遍引發衝突,有些瀏覽器兩個都沒有,會一個都加載不出來
- 經過動態添加 script 標籤,W3C 的標準規定動態添加的 script 標籤是異步的
- 這裏 src 部分的下載是異步的,不會阻塞後面的代碼執行,便可一邊把 script 插入到 DOM 中一邊下載資源
<script>
function loadScript(url, callback) {
const script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) {
script.onreadystatechange = function() {
if (script.readeyState === "loaded" || script.readeyState === "complete") {
script.onreadystatechange = null;
callback && callback();
}
}
} else {
script.onload = function() {
callback && callback();
}
}
script.src = url;
document.body.appendChild(script);
}
</script>
複製代碼