在HTML中我们会遇到以下三类script:
<script src = 'xxx'></script>
<script src = 'xxx' async></script>
<script src = 'xxx' defer></script>
那么这三类有什么区别呢?
script
浏览器在解析HTML代码时,如果遇到一个没有任何属性的script标签,就会暂停解析,先发送网络请求获取该JS脚本的代码内容,然后让JS引擎执行该代码,当代码执行完毕后再恢复。如下图所示:
从图中我们可以看到,script阻止了浏览器对HTML的解析,如果获取JS脚本的网络请求迟迟得不到回应,或者请求时间过长,就会导致白屏,用户看不到页面内容。
async script
当浏览器遇到async属性的script时,请求该脚本的网络是异步的,不会阻止浏览器解析HTML。
一旦网络请求回来之后,如果此时HTML还没有解析完,浏览器会暂停解析,先让JS引擎执行代码,执行完毕再进行HTML解析,如下图所示:
还有一种情况就是,如果在网络请求回来之前HTML解析完毕了的话,就可以正常执行JS代码啦
所以async的执行时间是不确定的,如果在异步JS脚本中获取某个DOM元素,有可能获取到也有可能获取不到,而且多个async同时存在的话,它们之间的执行顺序也是不确定的,完全依赖于网络请求的时间,谁先到就执行谁
defer script
defer表示延迟,当浏览器中遇到带有defer属性的浏览器时,获取该脚本的网络请求也是异步的,但它不会阻止浏览器解析HTML。
一旦网络请求回来之后,如果此时HTML还没有解析完毕,浏览器不会暂停解析并执行JS代码(与async不同),而是等待HTML全部解析完毕再执行JS代码,如下图所示:
如果存在多个 defer script 标签,浏览器(IE9及以下除外)会保证它们按照在 HTML 中出现的顺序执行,不会破坏 JS 脚本之间的依赖关系。
最后,不同script执行顺序以及是否阻止HTML解析总结如下: