script中的async和defer
defer: This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed.
sync: Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously.
defer
对于defer,我们可以先思考一个情况。一个页面如果有N个外链的脚本,放在head中,那么,当加载脚本时会阻塞页面的渲染,也就是常说的空白。
如果在 <head>
中, 通过 <script>
标签引用js文件,那么在这些js加载并执行完之前,浏览器不会继续往下解析html,用户就会看到所谓的白屏; <script defer src="my.js">..</script>
,带 defer属性的 script
,即使放在 head
里面, 它也会等到html解析完成(DOMDocumentLoaded)之后再执行,类似把 script
放在了页面底部。
async
<script async src="my.js"></script>
, async属性类似defer, 也会让脚本异步加载,不会阻塞html的往下解析;但是async加载的js,会在加载完时立即执行,所以脚本之间的执行顺序无法保证, 适用于无依赖(不依赖也不被依赖)的脚本。
//没有 defer 或 async,
//浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,要先完成JS的加载并执行。
<script src="script.js"></script>
//有 async,加载和渲染后续文档元素和 script.js 的加载与执行并行(异步)。
//同时script.js会在加载完后,立即执行
<script async src="script.js"></script>
//有 defer,加载后续文档元素将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
<script defer src="myscript.js"></script>
从实用角度来说呢,把所有脚本都丢到 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析; 但有些时候我们有确实需要async 和defer属性,实现异步加载脚本,避免后续DOM的渲染被阻塞。
具体区别,这张图说明的很清楚:
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics