[HTML] <script>中defer跟async是什麼?

realdennis
4 min readDec 13, 2018

--

在HTML5以前,script標籤沒有這兩個屬性,而瀏覽器單純的依照順序解析(parsing)並執行,HTML5之後,我們可以在script標籤定義他的行為,包括網路請求是否同步,執行時機等等。

給直接想知道答案的:

async 會非同步去請求外部腳本 回應後停止解析執行腳本內容

defer 也會非同步請求外部腳本 但是等待瀏覽器解析完才執行 (而且早於DOMContentLoaded 參考MDN)

想明白一件事情,應該沿著歷史脈絡去探討這功能 — 誕生的原因與其脈絡。

所以我們先來討論一下最legacy,什麼也不加的case吧。

什麼都不加的狀況中,瀏覽器一旦解析到<script src=”example.com”>會依照以下操作:

  1. 停止解析
  2. 對src發起請求
  3. 等待
  4. 執行回應腳本 或是 請求失敗Exception
  5. 繼續向下解析

在以上一系列的操作中,可以知道1–5之間會有一些網路延遲,會導致整個瀏覽器解析卡死,無法繼續渲染。

當你的使用者等了一段時間畫面還是白的…於是按下F12並打下history.back()時

但在當時,少數能做的只有選擇優秀的CDN,或是將script放在body閉合前的位置

我們可以從以上的分析中知道這種問題多煩,而且解決方案多麼直觀,但在JavaScript的世界其實挺不直觀的,網路請求會不應該把其他無關的操作卡死。

於是我們的主角就出現了 — async & defer,這兩者都很棒,就像當年的AJAX崛起一樣,我們把請求射出去,繼續往下做其他事情,等到請求回來,再決定是否執行或是解析完在執行。

以下來一個說文解字

Photo by Kaleidico on Unsplash

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…

--

--