script标签中的属性defer、async总结

133 阅读1分钟

script 标签

<script> 标签是用于将 JavaScript 代码插入到 HTML 的主要方法。它具有内联和外部形式两种使用方式。

<script> 标签具有 src 属性的时候,标签内的代码会被忽略。

asyncdefer<script> 标签的可选属性。对于非模块脚本,只对外部脚本文件有效;对于模块脚本,async/defer 属性也适用于内联脚本。获取 async/defer 脚本的网络请求是异步的,不会阻塞浏览器解析 HTML。

html 解析 与 async/defer 的执行的顺序:

script的执行顺序.png

async

async 脚本保证会在页面的 load 事件之前执行,但可能会在 DOMContentLoaded 之前或之后执行,取决于网络请求快慢。

  • 网络请求完成之后,如果此时 HTML 还没有解析完,浏览器会暂停解析,先执行 JS 脚本代码,执行完毕后再解析 HTML。
  • 如果在脚本请求完成之前,HTML 已经解析完毕了,那就会立即执行 JS 脚本代码。

如果存在多个 async 脚本的时候,它们之间的执行顺序不确定,完全取决于谁先下载完毕。

对于 XHTML 文档,指定 async 属性时应该写成 async="async"

defer

defer 脚本在 DOMContentLoaded 事件之前执行。

  • 网络请求完成之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析 HTML,而是等待 HTML 解析完毕再执行 JS 代码。

HTML5 规范要求脚本应该按照它们出现的顺序执行。

对于 XHTML 文档,指定 defer 属性时应该写成 defer="defer"

在 esm 脚本中的表现形式

浏览器对于带有 type="module" 的模块脚本的加载规则与 <script defer> 的加载规则一致。当 HTML 解析到 <script type="module"> 标签后不会阻塞解析,并延迟到文档解析完成之后执行相应代码。

如果网页有多个 <script type="module">,它们会按照在页面出现的顺序依次执行。

如果在模块脚本里加上 async 属性,当所有依赖加载完成后立即停止 HTML 解析并运行相应代码。

<!-- 所有依赖都获取完成(analytics.js)然后脚本开始运行 -->
<script async type="module">
  import {counter} from './analytics.js';
  counter.count();
</script>