script标签中的defer和async使用技巧说明
藏锋de刃 人气:0script
标签用于加载脚本与执行脚本,在前端开发中可以说是非常重要的标签了。
直接使用script
脚本的话,html
会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM
渲染。
普通script:
- 文档解析的过程中,如果遇到
script
脚本,停止页面的解析渲染,下载script脚本。 - 如果是多个script脚本, 近似于同时并行下载script脚本。(虽然说是遇到script脚本, 就停止后面标签的解析渲染; 但chrome做了优化, 遇到script脚本, 会快速的查看后边有没有需要下载其他资源的, 一起并行下载, 为了节省一部分下载的时间。)
- 不论script脚本哪个先下载好, 都按照html中的先后顺序依此执行。 即如果后面的script脚本先下载好, 要等前面的script脚本下载好并执行后, 才能执行。
- 执行script脚本时, 也是停止页面的解析渲染。
- 执行完script脚本, 继续页面的解析渲染。
- 执行完script脚本和页面解析渲染完, 才会依此触发DOMContentLoaded, loaded事件
普通script总结:
- 1.普通script的下载和执行都阻塞页面的解析渲染。
- 2. 多个script的下载是并行, 但按照页面中顺序依此执行。
- 3. 考虑到不支持defer和async的老浏览器, 最佳实践是script放在body底部, 避免阻塞页面的解析渲染。
- 4.执行完script脚本, 继续页面的解析渲染。页面解析渲染完, 才会触发DOMContentLoaded。所以普通script脚本的下载和执行如果慢, 会延迟
DOMContentLoaded
事件的触发时间。
defer:
- 文档解析时,遇到设置了
defer
的script脚本,就会在后台进行下载,下载并不会阻止文档的解析渲染。 - 如果是多个设置了defer的script脚本, 近似于同时并行下载defer脚本。
- 当页面解析渲染完毕后,会等到所有的
defer
脚本下载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded
事件。 - 如果defer脚本下载较快, 会等到页面解析渲染完毕后, 才按照顺序执行defer脚本。执行完毕后会触发
DOMContentLoaded
事件。 - 如果defer脚本下载较慢, 在下载完前,页面解析渲染已完毕; 等defer脚本下载完后,才按照顺序执行defer脚本。执行完毕后会触发
DOMContentLoaded
事件。
defer 总结:
- 1.
defer
脚本的下载和执行都不会阻塞页面的解析渲染。因为等到页面的解析渲染完毕后,defer脚本才执行, 所以defer
脚本执行也不会阻塞页面的解析渲染。 - 2. 多个
defer脚本
的下载是并行, 但按照顺序依此执行。 - 3. 等页面的解析渲染完毕后,触发
DOMContentLoaded
事件前,defer脚本才依次执行。 所以defer脚本的下载和执行如果慢, 会延迟DOMContentLoaded
事件的触发时间。 - 4. 考虑有的浏览器不支持 defer场景, 多个defer脚本不一定会按照顺序执行, 最佳实践是只使用一个defer脚本。
defer推荐使用场景:
如果你的脚本代码依赖于页面中的DOM
元素(文档是否解析完毕),或者被其他脚本文件依赖。
例:
- 1. 评论框
- 2.代码语法高亮
- 3.
polyfill.js
async:
- 文档解析时,遇到设置了
async
的script脚本,就会在后台进行下载,下载并不会阻止文档的解析渲染。 - 如果是多个设置了async的script脚本, 近似于同时并行下载async脚本。
- async脚本的执行会阻止文档的解析渲染。
- 哪个async脚本先下载完, 就立刻执行,执行时阻止文档的解析渲染。async脚本执行顺序不按照页面中的脚本先后顺序。
async
脚本的下载和执行不计入DOMContentLoaded
事件统计。- 因async脚本下载不阻塞文档的解析渲染;如果async脚本下载较快, 趁async脚本下载很短时间内, 文档的解析渲染未完成, async下载后立即执行,执行时会阻塞文档的解析渲染; 执行后, 继续文档的解析渲染, 等页面的解析渲染完毕后,触发
DOMContentLoaded
事件。这种场景, async脚本的执行如果慢, 会延迟DOMContentLoaded
事件的触发时间。 - 如果async脚本下载较慢, 当async还在下载时, 文档的解析渲染已完成,这时不会等待async的下载, 会直接触发
DOMContentLoaded
事件。这种场景, async脚本的下载和执行不会延迟DOMContentLoaded
事件的触发时间。
async总结:
- 1.
async
脚本的下载不会阻塞页面的解析渲染。async
脚本的执行会阻塞页面的解析渲染。 - 2. 多个
async脚本
的下载是并行, 但执行不按照页面中的脚本先后顺序。哪个async脚本先下载完, 哪个async脚本就先立刻执行。 - 3.
async
脚本的下载和执行不计入DOMContentLoaded
事件统计。 - 4. async脚本的执行有可能在
DOMContentLoaded
事件前, 也有可能在DOMContentLoaded
事件后。 - 5. 当async脚本的执行在
DOMContentLoaded
事件前时,async
脚本的执行时间才会影响DOMContentLoaded
事件的触发时间。又因为脚本的执行时间一般都比较短, 所以可以认为async脚本基本不影响DOMContentLoaded
事件的触发时间。
async推荐使用场景:
如果你的脚本并不关心页面中的DOM
元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。
例:
1. 百度统计和Google Analytics
普通script, defer, async同时存在页面中:
- 1. 普通script执行完, 继续页面解析渲染;页面解析渲染完, 才触发
DOMContentLoaded
事件。 - 2.
defer
脚本是在页面解析渲染完,DOMContentLoaded
事件的触发前, 才执行defer脚本。 - 3. 由于1,2这两点, 所以一定先执行普通script, 再执行defer脚本。
- 4.
async
脚本的下载和执行不计入DOMContentLoaded
事件统计。 - 5.
async
脚本下载完, 就立刻执行, 且多个async脚本执行不按照页面中的脚本先后顺序。
由于4,5这两点, 所以async脚本执行与普通script, defer脚本无关, 那个时间点都有可能执行。
注意:defer,async只对外联script脚本文件有效, 内联script脚本设置无效。
加载全部内容