一、背景
浏览器构建 DOM
树过程中遇到 script
标签就会暂定构建,并开始下载脚本,执行脚本,之后再持续构建 DOM
树。
并且绝对于文档,往往脚本文件体积大,并且网络下载的耗时比解析 DOM
树要大得多。
1.1 script
标签的影响
阻塞浏览器构建 DOM
树(即便脚本并不会调用 document.write
),用户看到白屏(严格说是script
标签前面的页面局部)工夫比拟长。
1.2 最佳实际
把 script
标签放到 body
标签最初。
二、defer
通知浏览器能够异步下载内部脚本,不必期待下载执行,能够持续构建 DOM
树,等 DOM
树构建实现后才执行脚本。
下载 :后盾并行下载(异步下载)
执行 :DOM
构建后,但在 DOMContentLoaded
事件触发前
多个 defer
依照书写程序顺次串行形式执行。
defer
不会阻塞 DOM
树构建,然而会阻塞 DOMContentLoaded
事件触发。
三、async
通知浏览器能够异步下载内部脚本,不必期待下载执行,能够持续构建 DOM
树,并且下载实现后就能够执行了。
针对齐全独立的脚本。不会依赖其余脚本,同时其余脚本也不能依赖 async
脚本。
下载 :后盾并行下载(异步下载)
执行 :下载完就执行了。无需期待其余脚本,即先加载完的先执行。async
之间,以及和 DOMContentLoaded
事件处理函数执行程序是无序的。
留神 :因为 JS 是单线程的如果在执行async
脚本,此时其余工作就得暂定了,比方 DOM 树构建(不过这种状况很少见,除非 JS 脚本下载很快,并且 DOM 很大)
四、总结
下载程序 | 执行程序 | DOMContentLoaded | |
---|---|---|---|
async |
异步并行下载,不阻塞 DOM 树构建 |
先加载完的先执行(Load-first Order) | 跟 DOMContentLoaded 无关,执行程序不定 |
defer |
同async |
DOM 构建后,依据文档程序顺次串行执行 | 在 DOM 树构建后,但 DOMContentLoaded 事件触发前执行 |
相同点
- 都不会阻塞
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
指异步执行(执行程序不固定)
五、动静增加的脚本行为
5.1 通过 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
。
5.2 通过 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>
六、Issues
6.1 同时增加 async
, defer
的成果呢?
- 依照
async
成果执行; - 因为
async
是 HTML5 才提出的,而defer
是 HTML4 就有了,所以defer
比async
有更好的兼容性。同时增加async
,defer
的另一个成果是如果浏览器不反对async
,则降级为defer
; - 最佳实际就是把
script
标签放到body
标签最初,避免浏览器不反对async
,也不反对defer
。
参考
整顿自 GitHub 笔记 Scripts: async, defer