[HTML] <script>中defer跟async是什麼?
在HTML5以前,script標籤沒有這兩個屬性,而瀏覽器單純的依照順序解析(parsing)並執行,HTML5之後,我們可以在script標籤定義他的行為,包括網路請求是否同步,執行時機等等。
給直接想知道答案的:
— async 會非同步去請求外部腳本 回應後停止解析執行腳本內容
— defer 也會非同步請求外部腳本 但是等待瀏覽器解析完才執行 (而且早於DOMContentLoaded 參考MDN)
想明白一件事情,應該沿著歷史脈絡去探討這功能 — 誕生的原因與其脈絡。
所以我們先來討論一下最legacy,什麼也不加的case吧。
什麼都不加的狀況中,瀏覽器一旦解析到<script src=”example.com”>會依照以下操作:
- 停止解析
- 對src發起請求
- 等待
- 執行回應腳本 或是 請求失敗Exception
- 繼續向下解析
在以上一系列的操作中,可以知道1–5之間會有一些網路延遲,會導致整個瀏覽器解析卡死,無法繼續渲染。
但在當時,少數能做的只有選擇優秀的CDN,或是將script放在body閉合前的位置。
我們可以從以上的分析中知道這種問題多煩,而且解決方案多麼直觀,但在JavaScript的世界其實挺不直觀的,網路請求會不應該把其他無關的操作卡死。
於是我們的主角就出現了 — async & defer,這兩者都很棒,就像當年的AJAX崛起一樣,我們把請求射出去,繼續往下做其他事情,等到請求回來,再決定是否執行或是解析完在執行。
以下來一個說文解字吧
async —其實是asynchronous(非同步)的縮寫,非同步的發起請求,並且腳本回來之後,停止解析執行腳本,執行後恢復解析。
(用JS的非同步事件去想就挺直觀的)
- async操作沒有辦法確保DOM都已經全部渲染
- 操作DOM可能等於找死,會QQ饅頭等著吃exception
- 所以這種async你比較常會在google analytics上看到,而非UI類庫。
- 請求回來的執行是會停止browser parsing喔
defer —其實是deferred(延遲)的縮寫,非同步的把請求射出去,然後再確保DOM全部都解析完畢之後執行,在DOMContentLoaded之前。
(直接射後不理,好球啦。)
- 腳本執行時,可以確保DOM已經完整渲染
- 在DOMContentLoaded前先去執行
反過來說,如果我們要有非同步的好處,又想要確保DOM已經被渲染完,我們就簡單的告訴瀏覽器,我們想要延遲(deffered)一波,這樣就可啦,這樣放哪理論上都不會出事了。
以上討論的屬性在沒有src屬性的狀況下(比如行內腳本),將失去作用。
順帶抱怨一下,這篇文章我按Publish按了快10次,然後Medium一直給我Error occurs,結果一看console發現是403…