async 和 defer 属性在scirpt标签中的现在已被广泛支持,是时候确切地了解下他们的区别了。
图例
<script>
首先定义没有任何属性的 <script>。当html文件在解析时,遇到到这样的js标签时,会被阻塞,此时,解析将停止,并且将发起一个js文件的网络请求(假设这个个js标签是个外链js文件)。然后在html继续解析之前会执行该js文件。
<script async>
async 属性会使得html解析和js文件下载并行执行(不会被阻塞),但是当js文件下载完成会立即执行(会阻塞html文件解析),不保证执行顺序(不和在html文件中顺序一样,哪个脚本先下载完会先执行)
<script defer>
defer 属性会使得html解析和js文件下载并行执行(不会被阻塞),下载过程同 async 属性,会在html完成解析后再去执行。 defer 脚本执行会保证执行顺序(和在html文档中顺序保持一致)。
什么时候该用哪个属性
一般来来说,优先使用 defer ,然后是 async ,最后在没有属性的。这里有一些常用规则:
- 如果一些脚本不依赖于任何其他模块可以使用 async (不必保证执行顺序,比如google-analytics.js文件)
- 如果一些脚本依赖别的模块或者被别的模块依赖,我们应该使用 defer (可以保证执行顺序)
- 如果一些脚本文件很小并且被别的 async 所依赖,请使用没有属性的 script 标签,并且放在 async 上边
支持
defer 属性的实现在IE9以及以下版本有一些bug,就是不能保证执行顺序。如果你需要支持 IE9以及以下,一点也不推荐使用 defer ,如果执行顺序很重要,请使用没有属性的 script 标签
注意
当你同时指定了 defer 和 async ,async 在现代浏览器优先级会更高,当老的浏览器支持 defer 而不支持 async 将会回退到 defer。
这俩属性只有在你的script在head标签中有效,并且只适用于外链的js标签,当你把script放到body标签底部是没有任何作用的。
defer 脚本会在DOMContentLoaded和load事件之前执行 。
async 脚本会在 load 事件之前发生,但不能保证 DOMContentLoaded 事件先后的执行顺序