script标签的位置决定了页面何时渲染,浏览器解析页面时,碰到script标签会将脚本解析完后再解析后面的html、script。
所以我们在往页面里写script标签时建议不要将script标签放在head内,而是尽量放在body之前,其他html标签之后。这样的好处是页面白屏时间会缩短,优先解析出html。
定义
红宝书对这两个属性的解释如下:
defer
这个属性的用途是表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>
元素中设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于DOMContentLoaded
事件执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在DOMContentLoad
事件触发前执行,因此最好只包含一个延迟脚本。
async
这个属性与defer类似,都用于改变处理脚本的行为。同样与defer类似,async只适用于外部脚本文件,并告诉浏览器立即下载文件。但与defer不同的是,标记为async的脚本并不保证按照它们的先后顺序执行。
第二个脚本文件可能会在第一个脚本文件之前执行。因此确保两者之间互不依赖非常重要。指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。
MDN上的解释如下:
- async,该布尔属性指示浏览器是否在允许的情况下异步执行该脚本。该属性对于内联脚本无作用 (即没有src属性的脚本)。
- defer,这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发
DOMContentLoaded
事件前执行。如果缺少 src 属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用。对动态嵌入的脚本使用async=false
来达到类似的效果。
关键点:当script标签中间有代码时,两个属性都不会起作用。
引用中这篇文章的图,描述页面加载的顺序:
绿色线代表 HTML 解析,蓝色线代表脚本网络读取,红色线代表脚本执行。
- 没有任何属性时,文档解析、网络读取、执行都是串行。
defer
时文档解析与网络读取并行,在文档解析后,DOMContentLoaded
事件触发之前执行async
则没有任何限制,文档解析时网络读取文件,读取完后立即执行。
使用时机与场景请自行琢磨~
优先级
当一个script标签内同时包含defer
与async
属性时,如下:
1 | <script src="xxx/xxx.js" async defer></script> |
此时只会触发async
,不会触发defer
,除非浏览器不兼容async
。
兼容性
IE | Chrome | Firfox | Safari | IOS Safari | Android | |
---|---|---|---|---|---|---|
async | 10+ | 8+ | 3.6+ | 5.1+ | 5.1+ | 3+ |
defer | 10+ | 8+ | 3.5+ | 5+ | 5.1+ | 3+ |
_*_ 以上 + 包含当前版本,如:ie10+表示含ie10