JS在html中的執行順序受script標簽處理方式影響,默認阻塞html解析。解決方案是使用defer或async屬性異步加載腳本。1.defer保證腳本按文檔順序執行,且在html解析完成后執行,適合依賴dom或需順序執行的腳本;2.async不保證執行順序,下載后立即執行,適合不依賴dom或順序無關的腳本。此外,避免阻塞還可將script放在body末尾、使用cdn、代碼分割、懶加載和tree shaking等方法。選擇合適的策略能有效優化頁面性能并提升用戶體驗。
JS代碼在HTML中的執行順序,簡單來說,就是瀏覽器解析HTML時,遇到<script>標簽的處理方式。默認情況下,瀏覽器會停止解析HTML,下載并執行JS代碼,執行完畢后再繼續解析HTML。這就是阻塞渲染的原因。而defer和async屬性,就是用來解決這個問題的。</script>
解決方案
defer 和 async 都是用來異步加載 JavaScript 腳本的,但它們的執行時機有所不同,直接影響到頁面渲染和用戶體驗。理解它們之間的差異是優化前端性能的關鍵。
立即學習“前端免費學習筆記(深入)”;
-
默認情況(沒有 defer 或 async): 瀏覽器會立即下載并執行腳本,在腳本執行完成之前,會阻塞 HTML 解析。
-
defer: 瀏覽器會并行下載腳本,但會按照它們在 HTML 中出現的順序執行,并且只有在 HTML 解析完成之后才會執行。這意味著腳本可以訪問完整的 DOM 結構。
-
async: 瀏覽器也會并行下載腳本,但是腳本下載完成后會立即執行,不會按照它們在 HTML 中出現的順序執行。這意味著腳本執行時,HTML 可能還沒有完全解析完成,因此腳本不應該依賴于特定的 DOM 結構。
簡單來說,defer 保證執行順序,async 不保證。
defer和async的區別?
這個問題可以從多個角度來理解。最核心的區別在于執行時機和執行順序。defer 腳本會延遲到整個頁面解析完畢后再執行,并且會按照它們在文檔中出現的順序執行。而 async 腳本一旦下載完成,就會立即執行,不會等待頁面解析完成,也不會按照文檔順序執行。
假設你有三個腳本:script1.js、script2.js 和 script3.js,它們都帶有 defer 屬性,那么它們會按照 script1.js、script2.js、script3.js 的順序執行。如果它們都帶有 async 屬性,那么它們的執行順序就無法預測,取決于哪個腳本先下載完成。
一個實際的例子:假設 script1.js 定義了一個全局變量 myVariable,script2.js 依賴于這個變量。如果這兩個腳本都使用了 async,那么 script2.js 可能會在 script1.js 之前執行,導致錯誤。而如果使用 defer,就可以避免這個問題。
什么時候使用defer,什么時候使用async?
這取決于你的腳本是否依賴于 DOM 結構和執行順序。如果你的腳本需要操作 DOM 元素,或者依賴于其他腳本的執行結果,那么應該使用 defer。例如,你的腳本需要使用 jquery 來操作 DOM,那么應該使用 defer,確保 jQuery 庫加載完成后再執行你的腳本。
如果你的腳本不依賴于 DOM 結構,也不依賴于其他腳本的執行結果,那么可以使用 async。例如,統計分析腳本,或者廣告腳本,它們通常不需要操作 DOM 元素,也不需要等待其他腳本執行完成。
但需要注意的是,async 腳本的執行可能會阻塞 onload 事件。onload 事件會在所有資源(包括腳本、圖片、樣式表等)加載完成后觸發。如果你的腳本使用了 async,那么 onload 事件可能會被延遲觸發,影響用戶體驗。
如何避免JS阻塞頁面渲染?
除了使用 defer 和 async 之外,還有其他一些方法可以避免 JS 阻塞頁面渲染。
-
將 <script> 標簽放在 </script>