script标签的async和defer

发布时间 2023-05-22 15:15:11作者: pangqianjin

可能会遇到以下三类的script标签

<script src='xxx'></script>
<script src='xxx' async></script>
<script src='xxx' defer></script>

使用 async 和 defer 属性有一些规则需要遵守,以确保正确加载和执行脚本:

  1. async 和 defer 属性只适用于外部脚本,即通过 src 属性加载的脚本。内联脚本不能使用这两个属性。

  2. async 和 defer 属性不会影响脚本的行为,只会影响脚本的加载方式。

  3. async 属性会异步加载脚本,并在加载完成后立即执行,不会阻塞页面渲染。但是,由于异步加载的脚本不一定按照在页面中出现的顺序执行,因此如果一个脚本依赖于另一个脚本,就需要使用其他方法来确保它们按照正确的顺序执行。

  4. defer 属性会异步加载脚本,并在 HTML 解析完成后按照顺序执行,但在执行脚本之前不会阻塞页面渲染。如果多个脚本都使用 defer 属性,它们会按照在页面中出现的顺序执行。

  5. 如果不需要异步加载脚本,可以不使用 async 和 defer 属性,但需要确保脚本的加载和执行不会阻塞页面渲染。

总之,使用 async 和 defer 属性能够提高页面加载速度,但需要根据具体情况选择合适的方式来加载和执行脚本,并遵守相应的规则。

浏览器在解析html时,遇到script标签

1. script标签没有async属性,也没有defer属性:

html暂停解析 -> 请求script -> 执行script -> 继续解析html

如果遇到一个没有async属性,也没有defer属性的 script 标签,就会暂停解析,先发送网络请求获取该 JS 脚本的代码内容,然后让 JS 引擎执行该代码,当代码执行完毕后恢复解析。整个过程如下图所示:
image
可以看到,script 阻塞了浏览器对 HTML 的解析,如果获取 JS 脚本的网络请求迟迟得不到响应,或者 JS 脚本执行时间过长,都会导致白屏,用户看不到页面内容。

2. script标签有async属性:

异步请求script -> 执行script -> 若html没有解析完 继续解析html

当浏览器遇到带有 async 属性的 script 时,请求该脚本的网络请求是异步的,不会阻塞浏览器解析 HTML,

  • 一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器会暂停解析,先让 JS 引擎执行代码,执行完毕后再进行解析,图示如下:
    image
  • 如果在 JS 脚本请求回来之前,HTML 已经解析完毕了,则立即执行 JS 代码,如下图所示:
    image

3. script标签带有defer属性

异步请求script -> 解析html -> 执行script

  • 当浏览器遇到带有 defer 属性的 script 时,获取该脚本的网络请求也是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码,图示如下:
    image
  • 如果存在多个 defer script 标签,浏览器(IE9及以下除外)会保证它们按照在 HTML 中出现的顺序执行,不会破坏 JS 脚本之间的依赖关系。

4. 总结

image

  • 如果脚本是模块化的并且不依赖任何脚本,那么使用async
  • 如果脚本依赖或被另一个脚本依赖,则使用defer(保证执行顺序)
  • 如果async脚本依赖于其他脚本,则这个其他脚本需要使用不设置任何异步的内联脚本, 对应下面第一种方法(被依赖的脚本需要先加载并执行,内联脚本会在HTML解析到它们时立即执行,并阻塞后面的HTML解析,直到它们执行完成)

如果一个async的script脚本依赖于其他脚本,可以使用以下两种方法来解决:

  1. 将async脚本放在其依赖的脚本之后:将async脚本放在HTML中所有依赖脚本之后,可以确保依赖脚本先加载并执行,然后再加载和执行async脚本。

  2. 使用defer属性:如果需要异步加载脚本,并且要确保在其依赖的脚本加载和执行完成后再执行,可以使用defer属性。defer属性告诉浏览器,该脚本在HTML解析完毕后才会执行,但是在DOMContentLoaded事件触发之前执行。这样可以确保依赖脚本在async脚本之前加载并执行完成。

无论哪种方法,都需要确保依赖脚本在async脚本之前加载和执行完成,以避免潜在的错误和问题。