HTML中的Javascript

<script>元素属性

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/javascripttext/ecmascript已废弃,因此其默认值为application/x-javascript,有效的其他值为application/javascriptapplication/ecmacript

    • type还有一个值为module: 则代码会被认为是ES6模块,而此时代码中次才能出现importexport关键字。当然,对于不支持ES6模块的浏览器,可以设置nomodule属性,而支持es6模块的浏览器则会不加载指定的脚本。如下所示:

      1
      2
      <script type="module" src="main.js"></script>
      <script nomodule src="fallback.js"></script>
  • 还有关于noncereferrerpolicy属性,这里不再赘述,用到了再查吧,先掌握上述属性。


关于无属性的script和带有asyncdefer属性的scirpt区别,请参考知乎上的一个问答,我觉得总结很不错,这里我搬运一下,原作者是山行者

问题:在html中会遇到以下三类script:

1
2
3
<script src='xxx'></script>
<script src='xxx' async></script>
<script src='xxx' defer></script>
  1. 先来看没有任何属性的script:浏览器在解析 HTML 的时候,如果遇到一个没有任何属性的script标签,就会暂停解析,先发送网络请求获取该 JS 脚本的代码内容,然后让 JS 引擎执行该代码,当代码执行完毕后HTML恢复解析。整个过程如下图所示:

无任何属性的script会阻塞html的解析

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

script异步请求不阻塞html解析,但一旦脚本请求完毕,则执行脚本可能会阻塞html解析

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

js脚本异步请求完毕前html解析已完毕,则不会造成html的解析被阻塞

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

  1. 最后来看defer script:defer本身有推迟、延期的意思。当浏览器遇到带有 defer 属性的 script 时,获取该脚本的网络请求也是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码,图示如下:

defer属性表示script不仅会异步请求,而且会延迟到html解析完毕后再执行

如果存在多个 defer script 标签,浏览器(IE9及以下除外)会保证它们按照在 HTML 中出现的顺序执行,不会破坏 JS 脚本之间的依赖关系。

因此总结如下:

script标签 js执行顺序 是否阻塞解析html
<script> 在html中的顺序 阻塞
<script async> 网络请求返回顺序 可能阻塞,也可能不阻塞
<script defer> 在html中书写的顺序 不阻塞

参考资料

  1. 图解 script 标签中的 async 和 defer 属性

评论