HTML中的Javascript
<script>元素属性

src属性: 指向要执行的脚本代码的外部文件,即其值为外部脚本地址。charset属性: 使用src属性指定的代码所使用的字符集。这个属性很少用,字符集如:UTF-8、ISO-8859-1等。crossorigin属性: 配置相关请求的CORS设置,默认不使用该属性,其属性值有:crossorigin="anonymouse": 表示对脚本文件中的请求中不设置用户凭据。crossorigin="use-credentials": 表示设置凭据标志,意味着发出的请求中会包含用户凭据。
integrity属性: 这个单词本身就是完整性、诚信的意思, 添加该属性则表示允许比对接收到的资源和指定的加密签名(是一个哈希值)以验证子资源完整性(SRI,subresource integrity)。若接收到的资源的签名和这个属性指定的签名不匹配,则页面会报错,脚本不会执行。
integrity属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。
type属性: 代替废弃的language属性,表示代码块中的脚本语言的内容类型(MIME,Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)。type的值默认是text/javascript,由于原先的text/javascript和text/ecmascript已废弃,因此其默认值为application/x-javascript,有效的其他值为application/javascript和application/ecmacript;type还有一个值为module: 则代码会被认为是ES6模块,而此时代码中次才能出现import和export关键字。当然,对于不支持ES6模块的浏览器,可以设置nomodule属性,而支持es6模块的浏览器则会不加载指定的脚本。如下所示:1
2<script type="module" src="main.js"></script>
<script nomodule src="fallback.js"></script>
还有关于
nonce和referrerpolicy属性,这里不再赘述,用到了再查吧,先掌握上述属性。
关于无属性的script和带有
async、defer属性的scirpt区别,请参考知乎上的一个问答,我觉得总结很不错,这里我搬运一下,原作者是南山行者。
问题:在html中会遇到以下三类script:
1 | <script src='xxx'></script> |
- 先来看没有任何属性的
script:浏览器在解析 HTML 的时候,如果遇到一个没有任何属性的script标签,就会暂停解析,先发送网络请求获取该 JS 脚本的代码内容,然后让 JS 引擎执行该代码,当代码执行完毕后HTML恢复解析。整个过程如下图所示:

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

当然,如果在 JS 脚本请求回来之前,HTML 已经解析完毕了,那就啥事没有,立即执行 JS 代码,如下图所示:

所以 async 是不可控的,因为执行时间不确定,你如果在异步 JS 脚本中获取某个 DOM 元素,有可能获取到也有可能获取不到。而且如果存在多个 async 的时候,它们之间的执行顺序也不确定,完全依赖于网络传输结果,谁先下载下来就执行谁。
- 最后来看
defer script:defer本身有推迟、延期的意思。当浏览器遇到带有 defer 属性的 script 时,获取该脚本的网络请求也是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码,图示如下:

如果存在多个 defer script 标签,浏览器(IE9及以下除外)会保证它们按照在 HTML 中出现的顺序执行,不会破坏 JS 脚本之间的依赖关系。
因此总结如下:
| script标签 | js执行顺序 | 是否阻塞解析html |
|---|---|---|
<script> |
在html中的顺序 | 阻塞 |
<script async> |
网络请求返回顺序 | 可能阻塞,也可能不阻塞 |
<script defer> |
在html中书写的顺序 | 不阻塞 |