前言:
JavaScript代码的加载和执行会阻塞下面HTML的渲染。
为了解决这个问题就出现了
< script>标签提供了两个属性:defer和async。
没有 defer async 属性
<script src="script.js"></script>
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
defer 属性
<script defer src="script.js"></script>
当Script中有defer属性时,文档解析和脚本加载是异步的,等文档解析完脚本才开始执行。因此,在< script>元素中设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
async 属性
<script async src="script.js"></script>
当Script中有async 属性时,文档解析和脚本加载也是异步的,脚本下载完成后会停止HTML解析,执行脚本,脚本解析完继续HTML解析。
当 defer 和 async 同时存在时
执行效果和 async 一致
图解
概括来讲,就是这两个属性都会使script标签异步加载,然而执行的时机是不一样的。async是乱序的,而defer是顺序执行,这也就决定了async比较适用于百度分析或者谷歌分析这类不依赖其他脚本的库。从图中可以看到一个普通的< script>标签的加载和解析都是同步的,会阻塞DOM的渲染,这也就是我们经常会把< script>写在< body>底部的原因之一,为了防止加载资源而导致的长时间的白屏,另一个原因是js可能会进行DOM操作,所以要在DOM全部渲染完后再执行。
区别
相同点:
- 加载文件时不阻塞页面渲染
- 对于inline的script(内联脚本)无效
- 使用这两个属性的脚本中不能调用document.write方法
- 有脚本的onload的事件回调
不同点:
- html的版本html4.0中定义了defer;html5.0中定义了async
- 浏览器兼容性
总结
简单的来说,使用这两个属性会有三种可能的情况
- 如果async为true,那么脚本在下载完成后异步执行。
- 如果async为false,defer为true,那么脚本会在页面解析完毕之后执行。
- 如果async和defer都为false,那么脚本会在页面解析中,停止页面解析,立刻下载并且执行。