本文详细解析HTML中script标签的async与defer属性。不加属性时脚本同步阻塞DOM;async异步下载但下载完立即执行;defer异步下载且等待DOM解析完成后执行。通过对比三者差异,解决外部脚本依赖导致的初始化报错问题,确保脚本按预期顺序加载与执行。
引言
一 引言
代码如下
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
在script标签中,async和defer是两个常用的属性。它们不能同时使用,且是否添加这两个属性会显著改变脚本的加载与执行规则。此前我对这一机制了解不够深入,导致在实际开发中遇到了脚本加载顺序引发的问题。
我在同一个页面中引用了两个script脚本,结构大致如下:
<script src="https://www.google.com/recaptcha/api.js"></script>
<script src="demo.js"></script>
需要注意的是,这两个script脚本均未添加async或defer属性。其中demo.js包含了谷歌人机验证(reCAPTCHA)的初始化代码。通常情况下,必须先加载必要的资源(如api.js),才能成功初始化验证码,这类似于使用jQuery前必须先引用jQuery库的逻辑。
然而,由于网络环境不稳定,尽管api.js的引用代码位于demo.js之前,其下载过程可能延迟,甚至比demo.js更晚完成。这导致demo.js在尝试初始化时因依赖缺失而报错。为解决此问题,我们需要引入async和defer属性,并明确它们的区别。
script属性async、defer与不加属性的区别
二 属性async、defer与不加属性的区别
不加属性的加载行为
1 不加属性
最常见的script引用方式是直接引用,不添加任何额外属性。此时,浏览器会立即下载并同步执行指定的脚本。在脚本执行完毕前,后续的DOM解析将被阻塞,无法继续加载。具体流程如下图所示:

async属性的加载行为
2 属性async
熟悉Ajax的开发者对async一词并不陌生,它代表异步。当script标签添加了async属性时,浏览器会异步下载脚本,但下载完成后会立即同步执行该脚本。
通俗来说,脚本的下载过程是异步的,不会阻塞DOM的加载;但一旦脚本下载完毕,浏览器会立即停止DOM解析,转而同步执行脚本。此时,DOM加载仍需等待脚本执行完成。具体流程如下图所示:

defer属性的加载行为
3 属性defer
与async类似,defer也属于异步下载脚本。不同之处在于,脚本下载完成后不会立即执行,而是等待DOM解析完成后才执行。相比async的执行方式,defer更加实用,因为它确保了脚本在DOM就绪后运行。加载顺序如下图所示:

明确了script属性async、defer以及不加属性的区别后,回到文章开头的问题。我希望api.js一定在demo.js之前加载完成,无论需要等待多久。因此,我们可以对代码进行如下修改:
<script src="https://www.google.com/recaptcha/api.js" async></script>
<script src="demo.js" defer></script>
至此,本文内容结束。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。