script
标签用于加载脚本与执行脚本,在前端开发中能够说是很是重要的标签了。
直接使用script
脚本的话,html
会按照顺序来加载并执行脚本,在脚本加载&执行的过程当中,会阻塞后续的DOM
渲染。html
如今你们习惯于在页面中引用各类的第三方脚本,若是第三方服务商出现了一些小问题,好比延迟之类的,就会使得页面白屏。
好在script
提供了两种方式来解决上述问题,async
和defer
,这两个属性使得script
都不会阻塞DOM
的渲染。
但既然会存在两个属性,那么就说明,这两个属性之间确定是有差别的。前端
若是
script
标签设置了该属性,则浏览器会异步的下载该文件而且不会影响到后续DOM
的渲染;
若是有多个设置了defer
的script
标签存在,则会按照顺序执行全部的script
;defer
脚本会在文档渲染完毕后,DOMContentLoaded
事件调用前执行。git
咱们作了一个测试页面,页面中包含了两个script
标签的加载,给他们都加上defer
标识。
P.S. 为了更直观,咱们给script1.js
添加了1s
的延迟,给script2.js
添加了2s
的延迟。
下图是页面加载的过程&script
脚本的输出顺序。
不难看出,虽然script1
加载用时虽然比script2
短,但由于defer
的限制,因此Ta只能等前边的脚本执行完毕后才能执行。github
async
的设置,会使得script
脚本异步的加载并在容许的状况下执行async
的执行,并不会按着script
在页面中的顺序来执行,而是谁先加载完谁执行。chrome
咱们修改测试页面以下:
遂获得了以下的结果,页面加载时长上,并无什么变化,毕竟都是异步加载的脚本。
可是咱们能够看到一个小细节,DOMContentLoaded
事件的触发并不受async
脚本加载的影响,在脚本加载完以前,就已经触发了DOMContentLoaded
。npm
咱们接着修改测试页面。加载一个没有延迟的script
脚本,使得脚本能够即时的加载完毕。
咱们要测试一下,若是async
脚本加载的足够快,是否会在DOMContentLoaded
以前就执行(这个实验是基于对async
的描述“在容许的状况下执行”的论证)。
同时为了保证测试的稳定性,咱们在script
脚本引入的后边添加了数千个空的div
节点,用来延长文档的渲染时间。
执行结果不出所料,若是给async
必定的时间,是有可能在DOMContentLoaded
事件以前就执行的。
P.S. 从上图中左上角的火焰图中,咱们也能看到,出现了多段的蓝色(更新:晚上写的时候懵了,紫色的才是渲染,蓝色的是解析)文档渲染。以及下边Console
的顺序。
说明的确,async
的执行是加载完成就会去执行,而不像defer
那样要等待全部的脚本加载完后按照顺序执行。浏览器
网上有了很多这种相似的图,可是基本都是拿一个script就举例的
未免太过寒酸,so我们来一个豪华版,来画一下多个脚本加载时的甘特图
就像近年来各大手机厂商,出新机都喜欢来一个X+X plus异步
拿四个不一样的颜色来标明各自表明的含义async
更正:文档渲染 应该为 文档解析post
文档解析的过程当中,若是遇到script
脚本,就会中止页面的解析进行下载(可是Chrome会作一个优化,若是遇到script
脚本,会快速的查看后边有没有须要下载其余资源的,若是有的话,会先下载那些资源,而后再进行下载script
所对应的资源,这样可以节省一部分下载的时间 @Update: 2018-08-17
)。
资源的下载是在解析过程当中进行的,虽然说script1
脚本会很快的加载完毕,可是他前边的script2
并无加载&执行,因此他只能处于一个挂起的状态,等待script2
执行完毕后再执行。
当这两个脚本都执行完毕后,才会继续解析页面。
文档解析时,遇到设置了defer
的脚本,就会在后台进行下载,可是并不会阻止文档的渲染,当页面解析&渲染完毕后。
会等到全部的defer
脚本加载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded
事件。
async
脚本会在加载完毕后执行。async
脚本的加载不计入DOMContentLoaded
事件统计,也就是说下图两种状况都是有可能发生的
若是你的脚本代码依赖于页面中的DOM
元素(文档是否解析完毕),或者被其余脚本文件依赖。
例:
polyfill.js
若是你的脚本并不关心页面中的DOM
元素(文档是否解析完毕),而且也不会产生其余脚本须要的数据。
例:
若是不太能肯定的话,用defer
老是会比async
稳定。。。
测试代码存放处:https://github.com/Jiasm/research-script-tagclone
后执行npm start
便可运行。
调试推荐使用chrome
无痕模式(这样才不会在Performance
页签上看到不相关的插件数据)。