1. 正常模式
<script src="index.js"></script>
這種情況下 JS 會阻塞 dom 渲染,瀏覽器必須等待 index.js 加載和執行完成后才能去做其它事情
2. async 模式
<script async src="index.js"></script>
async 模式下,它的加載是異步的,JS 不會阻塞 DOM 的渲染,async 加載是無順序的,當它加載結束,JS 會立即執行 使用場景:若該 JS 資源與 DOM 元素沒有依賴關系,也不會產生其他資源所需要的數據時,可以使用async 模式,比如埋點統計
3. defer 模式
<script defer src="index.js"></script>
- defer 模式下,JS 的加載也是異步的,defer 資源會在 DOMContentLoaded 執行之前,并且 defer 是有順序的加載
- 如果有多個設置了 defer 的 script 標簽存在,則會按照引入的前后順序執行,即便是后面的 script 資源先返回 所以 defer 可以用來控制 JS 文件的執行順序,比如 element-ui.js 和 vue.js,因為 element-ui.js 依賴于 vue,所以必須先引入 vue.js,再引入 element-ui.js
<script defer src="vue.js"></script>
<script defer src="element-ui.js"></script>
復制代碼
defer 使用場景:一般情況下都可以使用 defer,特別是需要控制資源加載順序時
4. module 模式
<script type="module">import { a } from './a.js'</script>
復制代碼
在主流的現代瀏覽器中,script 標簽的屬性可以加上 type="module",瀏覽器會對其內部的 import 引用發起 HTTP 請求,獲取模塊內容。這時 script 的行為會像是 defer 一樣,在后臺下載,并且等待 DOM 解析 Vite 就是利用瀏覽器支持原生的 es module 模塊,開發時跳過打包的過程,提升編譯效率
5. preload
<link rel="preload" as="script" href="index.js">
link 標簽的 preload 屬性:用于提前加載一些需要的依賴,這些資源會優先加載(如下圖紅框)
vue2 項目打包生成的 index.html 文件,會自動給首頁所需要的資源,全部添加 preload,實現關鍵資源的提前加載
preload 特點:
- preload 加載的資源是在瀏覽器渲染機制之前進行處理的,并且不會阻塞 onload 事件;
- preload 加載的 JS 腳本其加載和執行的過程是分離的,即 preload 會預加載相應的腳本代碼,待到需要時自行調用;
6. prefetch
<link rel="prefetch" as="script" href="index.js">
prefetch 是利用瀏覽器的空閑時間,加載頁面將來可能用到的資源的一種機制;通常可以用于加載其他頁面(非首頁)所需要的資源,以便加快后續頁面的打開速度
prefetch 特點:
- pretch 加載的資源可以獲取非當前頁面所需要的資源,并且將其放入緩存至少5分鐘(無論資源是否可以緩存)
- 當頁面跳轉時,未完成的 prefetch 請求不會被中斷
總結
- async、defer 是 script 標簽的專屬屬性,對于網頁中的其他資源,可以通過 link 的 preload、prefetch 屬性來預加載
- 如今現代框架已經將 preload、prefetch 添加到打包流程中了,通過靈活的配置,去使用這些預加載功能,同時我們也可以審時度勢地向 script 標簽添加 async、defer 屬性去處理資源,這樣可以顯著提升性能