瀏覽器構建DOM
樹過程中遇到script
標籤就會暫定構建,並開始下載腳本,執行腳本,以後再繼續構建DOM
樹。
而且相對於文檔,每每腳本文件體積大,而且網絡下載的耗時比解析DOM
樹要大得多。html
script
標籤的影響阻塞瀏覽器構建DOM
樹(即便腳本並不會調用document.write
),用戶看到白屏(嚴格說是script
標籤後面的頁面部分)時間比較長。html5
把 script
標籤放到body
標籤最後。git
defer
告訴瀏覽器能夠異步下載外部腳本,不用等待下載執行,能夠繼續構建DOM
樹,等DOM
樹構建完成後才執行腳本。github
下載:後臺並行下載(異步下載)
執行:DOM
構建後,但在DOMContentLoaded
事件觸發前
多個defer
按照書寫順序依次串行方式執行。
defer
不會阻塞DOM
樹構建,可是會阻塞DOMContentLoaded
事件觸發。瀏覽器
async
告訴瀏覽器能夠異步下載外部腳本,不用等待下載執行,能夠繼續構建DOM
樹,而且下載完成後就能夠執行了。
針對徹底獨立的腳本。不會依賴其餘腳本,同時其餘腳本也不能依賴 async
腳本。網絡
下載:後臺並行下載(異步下載)
執行:下載完就執行了。無需等待其餘腳本,即先加載完的先執行。async
之間,以及和DOMContentLoaded
事件處理函數執行順序是無序的。less
注意:由於JS是單線程的若是在執行async
腳本,此時其餘工做就得暫定了,好比DOM樹構建(不過這種狀況不多見,除非JS腳本下載很快,而且DOM很大)異步
下載順序 | 執行順序 | DOMContentLoaded | |
---|---|---|---|
async |
異步並行下載,不阻塞DOM 樹構建 |
先加載完的先執行(Load-first Order) | 跟DOMContentLoaded 無關,執行順序不定 |
defer |
同async |
DOM構建後,根據文檔順序依次串行執行 | 在DOM 樹構建後,但DOMContentLoaded 事件觸發前執行 |
相同點async
DOM
樹構建,都是異步下載,可讓用戶先看到頁面內容;document.write
,不然瀏覽器有個warning:Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
差別點函數
defer
和async
的惟一區別就是執行時間點不一樣。
defer
指推遲執行(執行順序不變)async
指異步執行(執行順序不固定)document.createElement('script')
方式添加腳本經過document.createElement('script')
方式建立的script
對象,其async
屬性默認爲true
。
let script = document.createElement('script'); console.log(script.async) // true console.log(script.defer) // false
若是顯示地設置script.async=false
,則行爲同defer
,即便此時script.defer=false
。
document.write('<script src="xxxx"><\/script>')
添加腳本document.write
自己的功能就是向文檔流裏插入內容,因此經過document.write('<script src="xxxx"><\/script>')
添加腳本的效果同直接在文檔裏寫script
標籤方式。
<script> document.write('<script defer src="./lib/normal.long.js"><\/script>') </script> <!-- 等價 --> <script defer src="./lib/normal.long.js"><\/script>
async
, defer
的效果呢?async
效果執行;async
是HTML5才提出的,而defer
是HTML4就有了,因此defer
比async
有更好的兼容性。同時添加async
, defer
的另外一個效果是若是瀏覽器不支持async
,則降級爲defer
;script
標籤放到body
標籤最後,防止瀏覽器不支持async
,也不支持defer
。