Skip to content
On this page

<script> 非同步資源載入與安全驗証

簡單說

  • defer 延遲 : 遇到 <script> 時,會非同步請求且下載,待 DOM 解析完才會執行。
  • async 非同步 : 遇到 <script> 時,會非同步請求腳本,下載後 暫停解析 DOM 先執行 script 腳本。

前言

瀏覽器讀取 html 時,是逐行向下解析,當遇到 <script> 就會暫停解析 DOM ,開始下載 <script> 完成 (下載) 後即刻執行, 再接續的向下 解析 DOM

為了避免DOM 還沒完全生成,就執行 <script> 所產生的問題,大家就會把 <script> 放在 <body> 的最後。

defer 延遲

script 加上 defer 屬性,是告訴瀏覽器就算下載完腳本,也持續解析、渲染畫面,不被要載入的 script 所影響;實際執行是在 DOMContentLoaded 之前,一樣是由上至下的順序執行腳本。

html
<script src="..." defer />

流程

  • 解析 DOM
  • 非同步請求腳本 (遇到 script)
  • 解析 DOM 完成 (DOMContentLoaded 之前)
  • 執行腳本

注意

defer 屬性雖然是 布林值 ,但在 IE9 中使用 defer="false"defer 還是會生效哦!

WARNING

如果已經加上 defer 就不要再內容加上 dom ready 的函式,這樣會影響其它 script 的下載與執行。

async 非同步

script 中加上 async 屬性,瀏覽器不停止解析 DOM 的情況,先 非同步 請求資源,當腳本下載完成,就會 停止解析 DOM 執行載入的腳本,後再接續解析。

html
<script src="..." async />

流程

  • 解析 DOM
  • 非同步請求腳本 (遇到 script)
  • 取得腳本
  • 停止解析 DOM
  • 執行腳本
  • 恢復解析 DOM

Integrity 資源驗証 (SRI)

當你的 <script> 使用外部載入、或第三方資源載入,就很難確保來源是否有受到 篡改, 如果受到惡意的篡改,當執行了載入的腳本就可能發生 資安 事件。

integrity 屬性,就可以用來確保載入的資源是否受到篡改;瀏覽器會比對下載的來源 integrity 值,是否與請求 integrity 相同,若不符就不會執行下載; 這個行為也稱 子資源完整性 Subresource Integrity (SRI)

html
<!-- 這是 jQuery 提供的 CDN -->
<script
  src="https://code.jquery.com/jquery-3.6.0.js"
  integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
  crossorigin="anonymous"
></script>

<!-- Bootstrap CDN -->
<script 
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" 
  integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" 
  crossorigin="anonymous"
></script>

使用方法

  • 設置 integrity 屬性 :

    遇到 <script> integrity="加密演算-base64",以 sha256 加密為範本。

    javascript
    integrity="sha256-2mQWTKbO3ljlTwwAlKs8Ooj/VVMdGTc2FhrEq9GFy0A="
    
    • SRI 產生器
    • 本機資源生成
      bash
      openssl dgst -sha256 -binary [YOUR FILE NAME.js] | openssl base64 -A
      
      編碼生成:
      bash
      47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
      

注意

當啟用了 SRI 策略,瀏覽器就會對資源做 CROS 檢查,需要在屬性加上 crossorigin="anonymous"

Reference: