深入理解 script 標簽的 async,defer 屬性(同步加載,異步加載,延遲執(zhí)行)
|
freeflydom
2025年11月1日 9:19
本文熱度 224
|
1. 異步加載 和 延遲執(zhí)行 存在的意義 : 避免影響 頁面渲染/顯示- 瀏覽器解析(渲染/顯示)的 阻塞問題
- 加載和解析 順序: 瀏覽器在 解析 HTML 頁面代碼時, 是 從上到下 依次 加載, 解析、渲染
- 阻塞 1: 外部腳本 js 文件的 加載和執(zhí)行, 影響 頁面渲染(顯示).
- 如果 , 在
<head>中 ,用<scrip> 引用了一個 外部腳本 js 文件<script src="home.js" type="text/javascript"></script>
- 而且這個 文件很大或者有問題,需要 2 秒的加載和執(zhí)行時間,那么在這個時間中, 瀏覽器 會停止渲染頁面,頁面就會是 白屏顯示,什么內(nèi)容 都沒有),2 秒后 腳本加載和執(zhí)行完成 才會繼續(xù)渲染頁面 ,頁面才顯示.
- 用戶體驗 差: 這個時候 用戶體驗就很不好,因為有幾秒什么也看不見,急脾氣的用戶,可能會直接關閉 頁面.
- 這種影響 頁面解析(渲染,顯示)的行為, 就是阻塞。
- 阻塞 2: 外部 css 文件的加載和執(zhí)行, 影響 頁面渲染(顯示).
CSS 文件 也一樣,因為 CSS 文件 會對DOM的 樣式,布局,色彩等外觀 產(chǎn)生影響,所以瀏覽器會等 CSS 文件 下載并執(zhí)行完成后 繼續(xù)。 為了頁面的性能,要避免阻塞。
2. 同步 加載和執(zhí)行 (影響 頁面解析/渲染/顯示)
- 示例1: 下圖, 是在 淘寶網(wǎng)的代碼中 截的圖,可以看到 把很多
<script>標簽 ,放在了 文檔底部的位置,在 文檔主體 結(jié)束標簽 </body> 之前.

- 示例2: 下圖,是在 MDN 網(wǎng)站的截圖, 也有
<script>標簽,被放在了 文檔的底部,</body> 標簽之前.

3. async 屬性: 異步加載 (不是 異步執(zhí)行,搭配 src 屬性,僅限 外部腳本)
- 示例1: 在MDN網(wǎng)站的 文檔頭部標簽
<head>中,也出現(xiàn)了 異步加載的 js文件 <script>
4. defer 屬性: 延遲執(zhí)行 (不是 延遲加載,加載是 并行的,搭配 src 屬性,僅限 外部腳本 )延遲執(zhí)行: defer - ① 并行獲取: 如果 異步加載
async屬性 不存在,而 延遲執(zhí)行defer屬性 存在,那么腳本將被 并行獲取 - ② 延遲執(zhí)行: 并在頁面完成解析后 進行執(zhí)行。
- 注意: 搭配
src 屬性,延遲執(zhí)行, 僅限 外部腳本
延遲執(zhí)行 defer的 加載和執(zhí)行 過程示例圖 - ① 加載:是并行的,不影響 頁面解析
- ② 執(zhí)行: 不是并行的, 但不會打斷 頁面解析,因為是在 頁面解析完成后 才執(zhí)行的.
- 加載和執(zhí)行,都不會打斷 頁面解析.

延遲執(zhí)行的 使用時機 - 延遲執(zhí)行:
- 有些
js代碼 并不是 頁面初始化的時候 就立刻需要的,而在 稍后的某些情況才需要的。 - 那么一開始 并不執(zhí)行 這些暫時不用的
js,而是在需要的時候 或稍后 再通過js 的控制來執(zhí)行,也不會影響。
根據(jù) js 的需要時機 進行分類: - 將
js 切分成許多模塊,頁面初始化時 只執(zhí)行 需要立即執(zhí)行的 js 可以使用 同步加載 ,可以放在head的script標簽中 - 其它 js ,可以延遲執(zhí)行。
- 比如, 頁面有大量不同的模塊 組成,很多可能 暫時不用或根本就沒用到。
- 就像圖片的延遲加載,在圖片出現(xiàn)在可視區(qū)域內(nèi)時(在滾動條下拉)才加載顯示圖片.
延遲加載: 除了延遲執(zhí)行,其實也可以設置 延遲加載,就是把 代碼片段,寫在 文檔的底部,</body>的前面,這樣 文檔按順序加載和解析的時候,到最后 才會加載這些代碼片段. 注意: defer只是 延遲執(zhí)行,并不是 延遲加載,在頁面解析的同時,就并行加載了,也不會影響頁面解析. 沖突事項: - 用了
defer不要使用 document.write() 方法;(為什么 ?因為涉及到 頁面顯示嗎?延遲執(zhí)行了,會影響頁面顯示?)
- 示例1: MDN 網(wǎng)站中,在 文檔的 底部,
</body>之前,就添加了 延遲執(zhí)行的 腳本文件.

- 示例2: 延遲加載 (無關
defer)- 如果 頁面 初始的渲染, 并不依賴于
js 或者 css, 可以用 延遲加載 - 即,最后加載
js, css代碼,把 引用外部文件的代碼 寫在最后 </body>前面。 - 比如,一些按鈕的 點擊事件,輪播圖動畫的腳本 也可以放在最后。
<html>
<head>
</head>
<body>
<script type="text/javascript" src="a.js"></script>
<link href="a.css" rel="stylesheet" />
</body>
</html>
5. 同步加載,異步加載,延遲執(zhí)行的 聯(lián)系和區(qū)別⑴ 同步加載,異步加載async,延遲執(zhí)行 defer的 加載 和 執(zhí)行 示例圖 - 綠色: 頁面解析(渲染/顯示)
- 藍色: 腳本 加載(下載/獲取)
- 紅色: 腳本執(zhí)行

① 同步加載的 加載和執(zhí)行 過程 - 加載:不是 并行的,會打斷 頁面解析
- 執(zhí)行: 不是 并行的, 會打斷 頁面解析
② 異步加載async的 加載和執(zhí)行 過程 - 加載:是并行的,不影響 頁面解析
- 執(zhí)行: 不是并行的, 會打斷 頁面解析
- 加載 不打斷頁面解析,★執(zhí)行 會打斷頁面解析.
③ 延遲執(zhí)行 defer的 加載和執(zhí)行 過程 - 加載:是并行的,不影響 頁面解析
- 執(zhí)行: 不是并行的, 但不會打斷 頁面解析,因為是在 頁面解析完成后 才執(zhí)行的.
- 加載和執(zhí)行,★都不會 打斷頁面解析.
⑵ 同時 指定 async,defer 屬性: (行為回退,避免 阻塞行為) - 行為 回退: 即使指定了 異步加載
async屬性,也可以指定 defer屬性- 回退到 延遲執(zhí)行: 以使 僅支持 延遲執(zhí)行
defer(而不支持 異步加載async)的遺留Web瀏覽器 退回到 延遲執(zhí)行defer行為,而不是 默認的阻塞行為。
⑶ 多個腳本的 執(zhí)行順序: - ① 同步加載
- 按順序: 放置在
<head>內(nèi)- 會阻塞
<body>的渲染, 會出現(xiàn)白屏,按照順序 立即執(zhí)行幾個腳本文件
- ★ 按順序: 放置在
<body>底部- 等
<body>中的內(nèi)容 渲染完畢后, 再加載, 順序執(zhí)行js<script>寫在<body>底部,沒有 兼容性問題,沒有 白屏問題,沒有 執(zhí)行順序問題.
- 是比較推薦的寫法,很多網(wǎng)站都在使用,比如 淘寶網(wǎng), MDN 網(wǎng)站等.
- ② 異步加載: 放置在
<head>頭部并使用async- 先加載完畢的 先執(zhí)行: 異步 并行加載資源,且加載完JS資源立即執(zhí)行,并不會按 js 文件的順序,誰快 誰先上
- ③ 延遲執(zhí)行: 放置在
<head>頭部并使用defer- 按 順序執(zhí)行: 異步 并行加載資源,在 DOM 渲染后,即,頁面解析完畢后, 再按順序執(zhí)行
js - HTML5 規(guī)范要求 腳本按照它們出現(xiàn)的 先后順序執(zhí)行,因此 第一個
defer 延遲腳本, 會先 于第二個延遲腳本執(zhí)行,而這兩個腳本 會先于 DOMContentLoaded 事件執(zhí)行。 - 在實際應用當中,延遲執(zhí)行的腳本 并不一定會按照 順序執(zhí)行,也不一定會在
DOMContentLoad 時間觸發(fā)前 執(zhí)行,因此最好只包含一個延遲腳本。
- ④ ★ 異步加載 和延遲執(zhí)行: 放置在
<head>頭部, 并同時使用async和defer- 表現(xiàn)和
async一致 - 不支持
async的,支持defer的,會表現(xiàn)得和defer一樣- 異步加載 比延遲執(zhí)行的 優(yōu)先級高些.
- 這種方法,也是比較推薦的,同時兼容 支持
async和defer 兩個屬性的 瀏覽器
⑷ 僅限 外部腳本: 腳本<script>標簽的 異步加載 async和 延遲執(zhí)行defer,都必須搭配 src 屬性,僅限 外部腳本 使用.
- 示例1: 在 MDN 網(wǎng)站中,也出現(xiàn)了 同時設置 異步加載和延遲執(zhí)行的
<script> 標簽. 
?轉(zhuǎn)自https://blog.csdn.net/VickyTsai/article/details/102841293
該文章在 2025/11/1 9:19:48 編輯過
|
|