script 标签中 defer 和 async

273 阅读4分钟

不加asyncdefer属性的加载和执行

image.png

  1. Attributes 的基本概念

    • 在 HTML 中,“attributes”(属性)是用于为 HTML 标签提供额外信息的一种机制。对于<script>标签来说,属性可以改变脚本的加载、执行行为以及和其他元素的交互方式等诸多特性。

async

image.png

defer

image.png

  1. 概念理解

    • defer属性script标签中的defer属性用于告诉浏览器这个脚本文件应该在文档解析完成后、DOMContentLoaded事件触发之前执行。可以把它想象成一个 “延迟执行但有序” 的指令。当浏览器遇到带有defer属性的script标签时,会继续解析 HTML 文档,构建 DOM 树,等 HTML 解析完成后,再按照script标签在文档中出现的顺序依次执行这些脚本。
    • async属性async属性则表示脚本是异步执行的。浏览器在遇到带有async属性的script标签时,会在后台继续解析 HTML 的同时,开始下载并执行这个脚本。脚本的执行顺序不确定,谁先下载完成谁就先执行,它更像是一种 “谁快谁先跑” 的机制。
  2. 加载和执行顺序对比

    • 假设有三个脚本文件script1.jsscript2.jsscript3.js,在 HTML 文件中有如下script标签设置:
     <script defer src="script1.js"></script>
     <script src="script2.js"></script>
     <script async src="script3.js"></script>
  • 对于script2.js(没有deferasync属性),浏览器会按照文档流的顺序,在解析到这个script标签时,停止 HTML 解析,先下载并执行script2.js,然后再继续解析后面的 HTML。

  • script1.js(带有defer属性)会在整个 HTML 文档解析完成后,按照它在文档中的顺序(在这个例子中是第一个)来执行,而且它的执行一定是在DOMContentLoaded事件触发之前。

  • script3.js(带有async属性)会在浏览器发现这个标签后,和 HTML 解析同时进行下载。一旦下载完成,就会立刻执行,不管 HTML 是否解析完成,也不考虑它在文档中的顺序。所以script3.js有可能在script1.jsscript2.js之前、之间或者之后执行。

  1. 对页面渲染的影响

    • defer属性:使用defer属性的脚本不会阻塞 HTML 文档的解析,这使得页面能够更快地构建 DOM 树,用户可以更快地看到页面的基本结构。因为脚本是在文档解析完成后才执行,所以可以确保脚本在操作 DOM 时,DOM 已经构建完成,不会出现找不到元素等问题。这种方式适用于那些依赖完整 DOM 结构的脚本,如对 DOM 元素进行事件绑定、初始化等操作的脚本。
    • async属性async属性的脚本同样不会阻塞 HTML 文档的解析(在下载阶段),但是由于它的执行顺序不确定,可能会在 DOM 尚未完全构建好的时候就开始执行。这可能会导致脚本在访问某些尚未创建的 DOM 元素时出现错误。它比较适合那些不依赖于页面 DOM 结构,或者可以在任何时候执行而不影响页面功能的脚本,比如一些统计代码、广告脚本等,这些脚本主要是发送数据给服务器,对页面的渲染和交互不是特别依赖。
  2. 使用场景推荐

    • defer的推荐场景

      • 当脚本用于初始化页面组件、添加事件监听器,并且这些操作需要完整的 DOM 结构时,使用defer是很好的选择。例如,一个 JavaScript 函数用于给页面中的所有按钮添加点击事件,这个脚本应该使用defer,这样可以确保在执行这个函数时,所有的按钮元素都已经在 DOM 中存在。
      • 对于多个相互依赖的脚本,并且需要按照一定顺序执行,defer也很合适。因为它能保证脚本按照在文档中的顺序执行,这样可以避免因执行顺序混乱而导致的错误。
    • async的推荐场景

      • 对于一些不依赖于页面 DOM 结构,只是用于收集数据、发送统计信息的脚本,如 Google Analytics 脚本等,async是理想的选择。这些脚本的主要目的是在后台发送数据,即使在页面还在渲染或者部分脚本还未执行的情况下,它们也可以正常工作。
      • 当对脚本的执行顺序没有严格要求,并且希望脚本尽快执行以减少页面加载时间(因为它不等待文档解析完成就可以开始下载和执行)时,也可以使用async。例如,一些独立的小工具脚本,它们之间没有相互依赖关系,并且对页面的渲染和交互影响较小。

END

deferanyscscript标签中用于控制脚本加载和执行顺序的两个重要属性,它们在优化网页性能和确保脚本正确执行方面发挥着关键作用。