谈谈script标签中的async和defer

script标签用于加载脚本与执行脚本,在前端开发中可以说是非常重要的标签了。
直接使用script脚本的话,html会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM渲染。
现在大家习惯于在页面中引用各种的第三方脚本,如果第三方服务商出现了一些小问题,比如延迟之类的,就会使得页面白屏。
好在script提供了两种方式来解决上述问题,async和defer,这两个属性使得script都不会阻塞DOM的渲染。
但既然会存在两个属性,那么就说明,这两个属性之间肯定是有差异的。

defer和async的的定义

defer:

这个属性的用途是表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置defer属性,相当于告诉浏览器立即下载,但延迟执行。
HTML5规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于DOMContentLoaded事件执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在DOMContentLoad时间触发前执行,因此最好只包含一个延迟脚本。

async:

这个属性与defer类似,都用于改变处理脚本的行为。同样与defer类似,async只适用于外部脚本文件,并告诉浏览器立即下载文件。但与defer不同的是,标记为async的脚本并不保证按照它们的先后顺序执行。
第二个脚本文件可能会在第一个脚本文件之前执行。因此确保两者之间互不依赖非常重要。指定async属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。

既然都提到了DOMContentLoad那就也说下:

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。
而onload要等到所有页面元素加载完成才会触发, 包括页面上的图片、视频等等。

really? demo走走就知道了

defer

我们做了一个测试页面,页面中包含了两个script标签的加载,给他们都加上defer标识。

P.S. 为了更直观,我们给script1.js添加了1s的延迟,给script2.js添加了2s的延迟。
在这里插入图片描述
下图是页面加载的过程&script脚本的输出顺序。

不难看出,虽然script1加载用时虽然比script2短,但因为defer的限制,所以Ta只能等前边的脚本执行完毕后才能执行。
在这里插入图片描述
-----------------------------------------------------------------------------------------------------

在这里插入图片描述

async

我们修改测试页面如下:
在这里插入图片描述
遂得到了如下的结果,页面加载时长上,并没有什么变化,毕竟都是异步加载的脚本。

但是我们可以看到一个小细节,DOMContentLoaded事件的触发并不受async脚本加载的影响,在脚本加载完之前,就已经触发了DOMContentLoaded

在这里插入图片描述
-----------------------------------------------------------------------------------------------------
在这里插入图片描述
-----------------------------------------------------------------------------------------------------
在这里插入图片描述
-----------------------------------------------------------------------------------------------------
在这里插入图片描述

我们接着修改测试页面。加载一个没有延迟的script脚本,使得脚本可以即时的加载完毕。

async的设置,会使得script脚本异步的加载并在允许的情况下执行
async的执行,并不会按着script在页面中的顺序来执行,而是谁先加载完谁执行。

我们要测试一下,如果async脚本加载的足够快,是否会在DOMContentLoaded之前就执行(这个实验是基于对async的描述“在允许的情况下执行”的论证)。
同时为了保证测试的稳定性,我们在script脚本引入的后边添加了数千个空的div节点,用来延长文档的渲染时间。
在这里插入图片描述

执行结果不出所料,如果给async一定的时间,是有可能在DOMContentLoaded事件之前就执行的。

在这里插入图片描述
说明的确,async的执行是加载完成就会去执行,而不像defer那样要等待所有的脚本加载完后按照顺序执行。

图解script中的defer与async

更正:文档渲染 应该为 文档解析
在这里插入图片描述

普通script

文档解析的过程中,如果遇到script脚本,就会停止页面的解析进行下载(但是Chrome会做一个优化,如果遇到script脚本,会快速的查看后边有没有需要下载其他资源的,如果有的话,会先下载那些资源,然后再进行下载script所对应的资源,这样能够节省一部分下载的时间)。

资源的下载是在解析过程中进行的,虽说script1脚本会很快的加载完毕,但是他前边的script2并没有加载&执行,所以他只能处于一个挂起的状态,等待script2执行完毕后再执行。

当这两个脚本都执行完毕后,才会继续解析页面。
在这里插入图片描述

defer

文档解析时,遇到设置了defer的脚本,就会在后台进行下载,但是并不会阻止文档的渲染,当页面解析&渲染完毕后。

会等到所有的defer脚本加载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded事件。

在这里插入图片描述

async

async脚本会在加载完毕后执行。

async脚本的加载不计入DOMContentLoaded事件统计,也就是说下图两种情况都是有可能发生的.
在这里插入图片描述
在这里插入图片描述

推荐的应用场景

defer

如果你的脚本代码依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖。

例:

  • 评论框
  • 代码语法高亮
  • polyfill.js

async

如果你的脚本并不关心页面中的DOM元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。

例:

  • 百度统计

如果不太能确定的话,用defer总是会比async稳定(0.0)

文章参考:
https://www.cnblogs.com/jiasm/p/7683930.html
https://juejin.cn/post/6844903560879013896
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/DOMContentLoaded_event

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值