defer和async是script標簽的兩個屬性,用于在不阻塞頁面文檔解析的前提下,控制腳本的下載和執行。
先了解瀏覽器的加載和渲染過程:
- 瀏覽器先通過HTTP協議請求服務器,服務器響應瀏覽器獲取HMTL文檔并開始從上到下解析,構建DOM樹;
- 在構建DOM樹過程中,如果遇到外聯的樣式或腳本聲明,會暫停HTML文檔解析,創建新的網絡連接,并開始下載樣式文件和腳本文件;
- 樣式文件下載完成后,構建CSSDOM;腳本文件下載完成后,解釋并執行,然后繼續解析文檔構建DOM樹。
-
完成文檔解析后,將DOM和CSSDOM進行關聯和映射,最后將視圖渲染到瀏覽器窗口。
在這個過程中,腳本文件的下載會阻塞文檔的解析,有時候會影響用戶體驗,所以就使用defer和async進行控制。
Paste_Image.png
1.當<script>沒有任何屬性。HTML文件在解析過程中遇到<script>標簽,HTML的解析將停止,并將請求獲取外部的js文件,并執行該腳本文件,執行完之后才繼續解析html。
2.如果加了async <script async>,瀏覽器在HTML解析過程中下載js文件,js加載完之后暫停HTML解析器,并執行js,js執行完之后再繼續解析HTML。也就是說加載和渲染后續文檔的過程,與js文件的加載并行。
3.<script defer>
defer在HTML解析過程中下載js文件,只有解析完HTML后才執行該js文件。有defer的腳本可以按照它們在文檔中出現的順序執行。defer使加載后續文檔元素的過程將和 js 的加載并行進行(異步),但js的執行要在所有元素解析完成之后。
有什么區別?
defer:
如果有多個聲明了defer的腳本,則會按順序下載和執行。
defer腳本會在DOMContentLoaded和load事件之前執行。
async:
如果有多個聲明了async的腳本,其下載和執行也是異步的,不能確保彼此的先后順序 .
async會在load事件之前執行,但并不能確保與DOMContentLoaded的執行先后順序.
什么時候應該用什么?
如果腳本是模塊化的,并且不依賴任何腳本,則使用async 。
如果腳本依賴或被另一個腳本依賴,那么使用defer 。
如果腳本很小并且被async腳本所依賴,那么使用在async腳本后面的內聯腳本。