script 標籤 defer 與 async

JS 加載.png

普通 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 中一邊下載資源
// 須要注意的是 readyState 的 if-else 必定要寫在 script.src = url 和 appendChild 以前
// 因電腦速度可能會很快,剛走到 src = url 部分就已經加載完畢了, 此時 readyState 已變成 loaded,後面就不會觸發 onreadystatechange 事件
// 若回調函數是寫在須要加載進來的文件裏的方法,須要把該方法放到匿名函數裏,這樣在語法解析時纔不會由於函數未聲明而報錯

<script>
    function loadScript(url, callback) {
        const script = document.createElement("script");
        script.type = "text/javascript";
        if (script.readyState) { // IE 和高版本的 chrome、firefox
            script.onreadystatechange = function() {
                if (script.readeyState === "loaded" || script.readeyState === "complete") {
                    script.onreadystatechange = null;
                    callback && callback();
                }
            }
        } else {
            script.onload = function() { // safari chrome opera firefox
                callback && callback();
            }
        }
        script.src = url;
        document.body.appendChild(script);
    }
</script>
複製代碼
相關文章
相關標籤/搜索