# defer和async的区别

# 一、没有 defer 或 async

<script src="script.js"></script>
1

浏览器会立即加载并执行指定的脚本;

“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

# 二、有 defer

<script  defer src="script.js"></script>
1

有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded事件触发之前完成。

# 三、有 async

<script  async src="script.js"></script>
1

加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。


然后从实用角度来说呢,首先把所有脚本都丢到 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。

defer和async过程

蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。

此图告诉我们以下几个要点:

  • 1、defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
  • 2、它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的
  • 3、关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
  • 4、async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行
  • 5、仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics

# 四、举例

在页面脚本引用的时候设置defer或者async,为什么会有这两个属相来辅助脚本加载那,因为浏览器在遇到script标签的时候,文档的解析会停止,不再构建document,有时打开一个网页上会出现空白一段时间,浏览器显示是刷新请求状态(也就是一直转圈),这就会给用户很不好的体验,defer和async的合理使用就可以避免这个情况,而且通常script的位置建议写在页面底部(移动端应用的比较多,这两个都是html5中的新属性)。

所以相对于默认的script引用,这里配合defer和async就有两种新的用法,它们之间什么区别那?

  • 1、默认引用
script:<script type="text/javascript" src="x.min.js"></script>
1

当浏览器遇到 script 标签时,文档的解析将停止,并立即下载并执行脚本,脚本执行完毕后将继续解析文档。

  • 2、async模式
<script type="text/javascript" src="x.min.js" async="async"></script>
1

当浏览器遇到 script 标签时,文档的解析不会停止,其他线程将下载脚本,脚本下载完成后开始执行脚本,脚本执行的过程中文档将停止解析,直到脚本执行完毕。

  • 3、defer模式
<script type="text/javascript" src="x.min.js" defer="defer"></script>
1

当浏览器遇到 script 标签时,文档的解析不会停止,其他线程将下载脚本,待到文档解析完成,脚本才会执行。

所以async和defer的最主要的区别就是async是异步下载并立即执行,然后文档继续解析,defer是异步加载后解析文档,然后再执行脚本,这样说起来是不是理解了一点了呢?

它们的核心功能就是异步,那么两种属性怎么去区分什么情况下用哪个呢?

# 五、推荐的应用场景

  • 1、defer

如果你的脚本代码依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖。 例如:

评论框

代码语法高亮

polyfill.js

  • async

如果你的脚本并不关心页面中的DOM元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。

例如:

1.百度统计

TIP

如果不太能确定的话,用defer总是会比async稳定。。。

# 六、总结

defer与async的区别是:

  • 前者要等到整个页面正常渲染结束,才会执行;

  • 后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。

  • 一句话,defer是“渲染完再执行”,async是“下载完就执行”。

  • 另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

  • 同时使用sync和defer,defer不起作用,sync生效。