前言
之前看一篇介绍script标签中defer和async区别的文章。今天想利用chrome浏览器的Performance面板把知识再次巩固一下
先来一张经典图
- 无属性。当解析到当前位置时,会暂停html解析,去下载script资源,然后执行,执行完毕后继续html解析
- defer属性。一边下载script资源一边进行html解析,当资源下载完毕后会等待html解析完成后再执行,不会占用html解析时间
- 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标签无任何属性分析完毕
总结
- html解析和外部资源下载是同步进行的
- js资源下载完成后会执行,执行期间会暂停html解析,执行完之后继续html解析
- 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属性会降低页面下载的优先级
总结
- 如果页面对于js资源有严格的执行顺序,最好不要使用async属性
- 资源下载完成后会立马执行,且会阻塞解析html(上图没有体现阻塞html,主要是因为资在第一个资源下载完成后html解析就已经完成了)
- 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解析完成后按照顺序执行,会降低下载资源的优先级
总结
- defer不阻塞html解析进度,资源全部下载完成后会按照顺序执行
- defer会影响资源下载的优先级
结语
- html解析和资源下载是同步进行的,并不是解析到当前位置才会触发下载
- script标签会阻塞当前html解析,当资源下载和执行完毕后继续html解析
- async和defer不阻塞html解析,区别是async属性在下载完成后会立即执行,执行顺序不能保证,执行时会阻塞html解析,defer则会在html解析完成后执行,会按照顺序执行
- js如果有严格的依赖关系则不能使用async
- 建议使用defer属性,既能保证执行顺序,也不阻塞html解析