乐趣区

关于javascript:Scripts-async-defer

一、背景

浏览器构建 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 事件触发前执行

相同点

  1. 都不会阻塞 DOM 树构建,都是异步下载,能够让用户先看到页面内容;
  2. 都不能够调用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.

差别点

  1. deferasync 的惟一区别就是执行工夫点不同。

    • 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 的成果呢?

  1. 依照 async 成果执行;
  2. 因为 async 是 HTML5 才提出的,而 defer 是 HTML4 就有了,所以 deferasync有更好的兼容性。同时增加 async, defer 的另一个成果是如果浏览器不反对async,则降级为defer
  3. 最佳实际就是把 script标签放到 body 标签最初,避免浏览器不反对async,也不反对defer

参考

整顿自 GitHub 笔记 Scripts: async, defer

退出移动版