通过chrome去了解html解析过程以及script标签defer、async区别

前言

之前看一篇介绍script标签中defer和async区别的文章。今天想利用chrome浏览器的Performance面板把知识再次巩固一下

先来一张经典图

  1. 无属性。当解析到当前位置时,会暂停html解析,去下载script资源,然后执行,执行完毕后继续html解析
  2. defer属性。一边下载script资源一边进行html解析,当资源下载完毕后会等待html解析完成后再执行,不会占用html解析时间
  3. async属性。一边下载script资源一边进行html解析,当资源下载完毕后会立即执行,执行期间html解析暂停,待执行完毕后继续html解析

主要区别:下载完成后是否立马执行,是否阻塞html解析

下面利用chrome浏览器的Performance面板来佐证上面的结论(下面分析均在无痕模式下进行,减少其他数据的干扰)

script依赖关系:bootstrap依赖jquery,backbone依赖underscore(backbone内部有些方法也依赖jquery,如果不调用就没事)

script标签无任何属性

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <link
      href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.css"
      rel="stylesheet"
    />
    <link
      href="https://cdn.staticfile.org/foundation/6.0.1/css/foundation.css"
      rel="stylesheet"
    />
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.17/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/2.0.0/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/js/bootstrap.js"></script>
  </head>
  <body>
    <ul>
      <li>这是li标签</li>
    </ul>
  </body>
  <script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
</html>

图1

从图中可以看出Parse HTML与资源下载是同时进行的,并不是说只有解析到相对应的外部资源才会去下载,这也是浏览器做的一个预解析器优化策略。

其中五个外部javascript资源,下载完成的顺序依次是backbone、bootstrap、underscore、jquery、vue

图2

图3 解析css资源

图4

当前html解析暂停,等待vue资源下载完成并执行后继续解析html(这里恰好是vue下载完后其余的js资源均下载完成了,所以只有一次html解析)

虽然别的资源早于vue下载完成,但是因为js资源是从上到下执行,所以必须要等到上一个资源执行完成之后才会继续执行下一个js

图5

这里是backbone下载较慢,所以执行完后面还要继续html解析

至此script标签无任何属性分析完毕

总结

  1. html解析和外部资源下载是同步进行的
  2. js资源下载完成后会执行,执行期间会暂停html解析,执行完之后继续html解析
  3. js资源是严格的按照从上到下的顺序执行,哪怕一些资源已经下载完毕,也要等上一个资源执行完之后才会执行

script标签:async

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <link
      href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.css"
      rel="stylesheet"
    />
    <link
      href="https://cdn.staticfile.org/foundation/6.0.1/css/foundation.css"
      rel="stylesheet"
    />
    <script
      async
      src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.17/vue.js"
    ></script>
    <script
      async
      src="https://cdn.bootcdn.net/ajax/libs/jquery/2.0.0/jquery.js"
    ></script>
    <script
      async
      src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/js/bootstrap.js"
    ></script>
  </head>
  <body>
    <ul>
      <li>这是li标签</li>
    </ul>
  </body>
  <script
    async
    src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-min.js"
  ></script>
  <script async src="https://cdn.bootcdn.net/ajax/libs/backbone.js/0.9.2/backbone-min.js"
  ></script>
</html>

图1

其中五个外部javascript资源,下载完成的顺序依次是vue、jquery、bootstrap、backbone、underscore

从图1可以看出,script执行顺序不再是按照书写的顺序执行,而是谁先下载完成谁执行,这种机制会导致js之间的依赖关系错乱,可能会导致某些内部js报错

图2

因backbone.js比underscore.js先执行,所以backbone.js内部报错

图3

async属性会降低页面下载的优先级

总结

  1. 如果页面对于js资源有严格的执行顺序,最好不要使用async属性
  2. 资源下载完成后会立马执行,且会阻塞解析html(上图没有体现阻塞html,主要是因为资在第一个资源下载完成后html解析就已经完成了)
  3. async会影响当前资源下载的优先级

script标签:defer

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <link
      href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.css"
      rel="stylesheet"
    />
    <link
      href="https://cdn.staticfile.org/foundation/6.0.1/css/foundation.css"
      rel="stylesheet"
    />
    <script
      defer
      src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.17/vue.js"
    ></script>
    <script
      defer
      src="https://cdn.bootcdn.net/ajax/libs/jquery/2.0.0/jquery.js"
    ></script>
    <script
      defer
      src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/js/bootstrap.js"
    ></script>
  </head>
  <body>
    <ul>
      <li>这是li标签</li>
    </ul>
  </body>
  <script
    defer
    src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.6/underscore-min.js"
  ></script>
  <script
    defer
    src="https://cdn.bootcdn.net/ajax/libs/backbone.js/0.9.2/backbone-min.js"
  ></script>
</html>

图1

图2

defer属性会使js资源在html解析完成后按照顺序执行,会降低下载资源的优先级

总结

  1. defer不阻塞html解析进度,资源全部下载完成后会按照顺序执行
  2. defer会影响资源下载的优先级

结语

  1. html解析和资源下载是同步进行的,并不是解析到当前位置才会触发下载
  2. script标签会阻塞当前html解析,当资源下载和执行完毕后继续html解析
  3. async和defer不阻塞html解析,区别是async属性在下载完成后会立即执行,执行顺序不能保证,执行时会阻塞html解析,defer则会在html解析完成后执行,会按照顺序执行
  4. js如果有严格的依赖关系则不能使用async
  5. 建议使用defer属性,既能保证执行顺序,也不阻塞html解析
相关推荐
薛定谔的算法2 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku3 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode3 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu3 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu3 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript
LuckySusu3 小时前
【js篇】深入理解 JavaScript 作用域与作用域链
前端·javascript
LuckySusu3 小时前
【js篇】call() 与 apply()深度对比
前端·javascript
LuckySusu3 小时前
【js篇】addEventListener()方法的参数和使用
前端·javascript
该用户已不存在3 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net
LuckySusu3 小时前
【js篇】深入理解 JavaScript 原型与原型链
前端·javascript