script 标签中 defer 和 async 的区别

357 阅读4分钟

在 HTML 中,<script> 标签用于引入外部 JavaScript 文件。为了优化页面加载性能,我们可以使用 deferasync 属性来控制脚本的加载和执行时机。

defer 属性

  • 含义: 延迟脚本执行,直到 HTML 解析完成。

  • 特点:

    • 脚本会按照在 HTML 中出现的顺序执行。
    • 不会阻塞 DOM 的构建。
    • 脚本会在 DOMContentLoaded 事件触发前执行。
  • 适用场景:

    • 脚本之间有依赖关系时,使用 defer 可以保证脚本按照正确的顺序执行。
    • 脚本需要在 DOMContentLoaded 事件触发前执行时,使用 defer

async 属性

  • 含义: 异步加载并执行脚本。

  • 特点:

    • 脚本的加载和执行不会阻塞 DOM 的构建。
    • 脚本可能在 HTML 解析完成之前或之后执行,顺序不确定。
  • 适用场景:

    • 脚本之间没有依赖关系时,使用 async 可以并行加载多个脚本,提高页面加载速度。
    • 脚本不需要在 DOMContentLoaded 事件触发前执行时,使用 async

两者对比

属性加载方式执行时机顺序阻塞DOM
defer异步DOMContentLoaded 事件前保证顺序不阻塞
async异步不确定不保证顺序不阻塞

Export to Sheets

示例

HTML

<script src="script1.js" defer></script>
<script src="script2.js" async></script>

Use code with caution.

  • script1.js 会在 HTML 解析完成后,按照在 HTML 中出现的顺序执行。
  • script2.js 会异步加载并执行,执行顺序不确定。

总结

  • deferasync 都可以异步加载脚本,不会阻塞 DOM 的构建。
  • defer 保证脚本按照顺序执行,适合有依赖关系的脚本。
  • async 不保证脚本执行顺序,适合没有依赖关系的脚本,可以并行加载多个脚本。

选择哪个属性取决于你的具体需求。 如果脚本之间有依赖关系,或者需要在 DOMContentLoaded 事件触发前执行,则使用 defer;如果脚本之间没有依赖关系,并且希望并行加载多个脚本,则使用 async

需要注意的是:

  • 如果脚本中使用了 document.write() 方法,则 deferasync 属性可能会失效。
  • 对于内联脚本(直接写在 <script> 标签中的脚本),deferasync 属性无效。

通过合理使用 defer 和 async 属性,可以优化页面加载性能,提升用户体验。

script 标签不加 defer 和 async 的执行方式

<script> 标签不添加 defer 和 async 属性时,浏览器会按照其在 HTML 中出现的顺序,同步加载并执行脚本。

具体执行过程:

  1. 遇到 浏览器会立即停止解析 HTML,开始下载并执行该脚本。
  2. 脚本执行完毕: 浏览器才会继续解析剩下的 HTML。

影响:

  • 阻塞 DOM 构建: 脚本的加载和执行会阻塞 DOM 的构建,导致页面渲染延迟,影响用户体验。
  • 影响后续脚本执行: 后续的脚本必须等到前面的脚本完全执行完毕后才能开始加载和执行。

示例:

HTML

<body>
  <p>这是第一段文字。</p>
  <script>
    console.log('第一个脚本');
    // 这里执行耗时的操作,会阻塞后续内容的加载
  </script>
  <p>这是第二段文字。</p>
</body>

在上面的例子中,浏览器会先加载并执行第一个脚本,然后才会显示第一段文字。如果第一个脚本执行时间较长,那么第二段文字的显示就会被延迟。

为什么不建议这么做?

  • 影响页面加载速度: 同步加载脚本会阻塞页面渲染,导致页面加载缓慢。
  • 降低用户体验: 用户需要等待脚本执行完毕才能看到页面内容。
  • 不利于 SEO: 搜索引擎会认为页面加载速度慢,从而降低页面排名。

总结

为了提高页面加载速度和用户体验,我们通常会使用 deferasync 属性来异步加载脚本。只有在脚本必须在 DOMContentLoaded 事件触发前执行,并且与其他脚本没有依赖关系时,才不需要使用这两个属性。

什么时候不加 defer 和 async?

  • 脚本必须在 DOMContentLoaded 事件触发前执行,并且依赖 DOM 结构时。 比如,需要获取页面元素的尺寸或操作 DOM 结构的脚本。
  • 脚本非常小,执行时间很短,不会对页面加载造成明显影响时。

建议:

  • 尽可能使用 defer 或 async 属性。
  • 将脚本放在 标签的底部,可以减少对页面渲染的影响。
  • 将脚本合并或压缩,减少 HTTP 请求次数。
  • 延迟加载不必要的脚本,比如统计脚本。

通过合理地使用 <script> 标签,可以有效地优化页面加载性能,提升用户体验。