Skip to content

script

普通脚本

浏览器在解析 HTML 的时候,如果遇到一个没有任何属性的 script 标签,就会暂停解析,先发送网络请求获取该 JS 脚本的代码内容,然后让 JS 引擎执行该代码,当代码执行完毕后恢复解析。

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

异步脚本

当浏览器遇到带有 async 属性的 script 时,请求该脚本的网络请求是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器会暂停解析,先让 JS 引擎执行代码,执行完毕后再进行解析。

所以 async 是不可控的,因为执行时间不确定,你如果在异步 JS 脚本中获取某个 DOM 元素,有可能获取到也有可能获取不到。而且如果存在多个 async 的时候,它们之间的执行顺序也不确定,完全依赖于网络传输结果,谁先到执行谁。

可以用于完全无依赖的脚本。

html
<script async src="file.js"></script>

通过脚本来做同样的事情(从脚本中创建的脚本默认为异步)。

js
var script = document.createElement('script')
script.src = 'file.js'
document.body.appendChild(script)

延迟脚本

当浏览器遇到带有 defer 属性的 script 时,获取该脚本的网络请求也是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码,执行时机将在文档完成解析后,触发 DOMContentLoaded 事件前执行,会按照他们在文档出现的顺序去下载解析。 有 defer 属性的脚本会阻止 DOMContentLoaded 事件,直到脚本被加载并且解析完成。效果和把 script 放在文档最后是一样的。

html
<script defer src="file.js"></script>

总结

  • defer 和 async 在下载时是一样的,都是异步的(相较 HTML 解析)。
  • defer 会在 HTML 解析完成后执行的,async 则是下载完成后执行。
  • defer 是按照加载顺序执行的,async 是哪个文件先加载完,哪个先执行。
  • async 在使用的时候,可以用于完全无依赖的脚本。