script标签中的defer和async
普通script:文档解析的过程中,如果遇到script脚本,停止页面的解析渲染, 下载script脚本。如果是多个script脚本, 近似于同时并行下载script脚本。不论script脚本哪个先下载好, 都按照html中的先后顺序依此执行。 即如果后面的script脚本先下载好, 要等前面的script脚本下载好并执行后, 才能执行。执行script脚本时, 也是停止页面的解析渲染。执行完sc
普通script:
- 文档解析的过程中,如果遇到
script
脚本, 停止页面的解析渲染, 下载script脚本。 - 如果是多个script脚本, 近似于同时并行下载script脚本。(虽然说是遇到script脚本, 就停止后面标签的解析渲染; 但chrome做了优化, 遇到script脚本, 会快速的查看后边有没有需要下载其他资源的, 一起并行下载, 为了节省一部分下载的时间。 )
- 不论script脚本哪个先下载好, 都按照html中的先后顺序依此执行。 即如果后面的script脚本先下载好, 要等前面的script脚本下载好并执行后, 才能执行。
- 执行script脚本时, 也是停止页面的解析渲染。
- 执行完script脚本, 继续页面的解析渲染。
- 执行完script脚本和页面解析渲染完, 才会依此触发DOMContentLoaded, loaded事件
总结:
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
事件。
总结:
1. defer
脚本的 下载和执行 都不会阻塞页面的解析渲染。因为等到页面的解析渲染完毕后, defer脚本才执行, 所以defer
脚本执行 也不会阻塞页面的解析渲染。
2. 多个defer脚本
的下载是并行, 但按照顺序依此执行。
3. 等页面的解析渲染完毕后, 触发DOMContentLoaded
事件前, defer脚本才依次执行。 所以defer脚本的下载和执行如果慢, 会延迟DOMContentLoaded
事件的触发时间。
4. 考虑有的浏览器不支持 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
事件的触发时间。
总结:
1. async
脚本的 下载 不会阻塞页面的解析渲染。async
脚本的 执行 会阻塞页面的解析渲染。
2. 多个async脚本
的下载是并行, 但执行不按照页面中的脚本先后顺序。哪个async脚本先下载完, 哪个async脚本就先立刻执行。
3. async
脚本的下载和执行不计入DOMContentLoaded
事件统计。
4. async脚本的执行有可能在 DOMContentLoaded
事件前, 也有可能在 DOMContentLoaded
事件后。
5. 当async脚本的执行在 DOMContentLoaded
事件前时, async
脚本的执行时间才会影响DOMContentLoaded
事件的触发时间。又因为脚本的执行时间一般都比较短, 所以可以认为async脚本基本不影响DOMContentLoaded
事件的触发时间。
推荐场景:
如果你的脚本并不关心页面中的DOM
元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。
例:
1. 百度统计和Google Analytics
普通script, defer, async同时存在页面中:
1. 普通script执行完, 继续页面解析渲染; 页面解析渲染完, 才触发DOMContentLoaded
事件。
2. defer脚本是在页面解析渲染完, DOMContentLoaded
事件的触发前, 才执行defer脚本。
由于1,2这两点, 所以一定先执行普通script, 再执行defer脚本。
4. async
脚本的下载和执行不计入DOMContentLoaded
事件统计。
5. async脚本下载完, 就立刻执行, 且多个async脚本执行不按照页面中的脚本先后顺序。
由于4,5这两点, 所以async脚本执行与普通script, defer脚本无关, 那个时间点都有可能执行。
ps:
defer,async只对外联script脚本文件有效, 内联script脚本设置无效。
更多推荐
所有评论(0)