async vs defer 的区别

1、why 两者

从事前端的小伙伴应该都知道,浏览器的渲染引擎负责解析服务器返回的一些 html、css 等资源,这些资源在未被解析之前都是以文本的形式存在,需要浏览器将对应的 html、css 解析成对应的 DOM、CSSOM 树,然后会将 DOM 和 CSSOM 合成为一棵 render 树,再经过 布局、绘制、合成 三个步骤将页面最总显示出来。

有一个问题,就是在浏览器解析 html 的过程中,如果遇到 <script> 标签的时候,浏览器就会停止解析 html,转而去执行 <script> 标签中的脚本,如果脚本中含有网络请求,那就会等网络请求完后再执行脚本中的代码,然后再回头继续解析 html。这样就造成了 html 解析被阻塞,从而导致页面渲染变慢。更严重是,如果在脚本中网络请求的资源恰好在一台网络情况较差的服务器上,这样整个网页的加载都会收到很大的影响。

举个例子:如果页面的 html 中,嵌入了一个 <script src="a.js"></script> 的标签,浏览器在解析到该便签时主要会做以下几个步骤:1. 停止解析 html、2.执行 a.js 中的脚本、3.如果 a.js 中有其他资源,则继续请求并执行、4.继续解析 html,由此就阻碍了 html 的解析。

为了针对上述的问题,就出现了 async 和 defer 两种解决方式。首先简要介绍一下:

两者都会并行下载 js,不会影响页面的解析,不同的是:

  • defer 会按照顺序在 DOMContentLoaded 前按照页面出现顺序依次执行脚本。
  • async 则是下载完立即执行。
  • 如果遇到 js 脚本中有 document.write(),则在上述两者的使用时,浏览器会发出警告。

2、async 

对于普通脚本,如果存在 async 属性,那么普通脚本会被并行请求,并尽快解析和执行。

对于模块脚本,如果存在 async 属性,那么脚本及其所有依赖都会在延缓队列中执行,因此它们会被并行请求,并尽快解析和执行。

该属性能够消除解析阻塞的 Javascript。举个例子:

<script src="b.js"async></script>
<script src="c.js"async></script>
  • 不阻止解析 document, 并行下载 b.js,c.js
  • 当脚本下载完后立即执行,两者执行顺序不确定,执行阶段不确定,可能在 DOMContentLoaded 事件前或者后

3、defer

这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。

有 defer 属性的脚本会阻止 DOMContentLoaded 事件,直到脚本被加载并且解析完成。举个例子:

<script src="d.js" defer></script>
<script src="e.js" defer></script>
  • 不阻止解析 document, 并行下载 d.js,e.js
  • 即使下载完 d.js, e.js 仍继续解析 document
  • 按照页面中出现的顺序,在其他同步脚本执行后,DOMContentLoaded 事件前 依次执行 d.js,e.js

4、总结

<script src="script.js"></script>:没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即“ 指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

<script async src="script.js"></script>:有 async,在加载和渲染后续文档元素的过程时,将和 script.js 的加载与执行并行进行(异步),如果脚本中涉及操作 DOM 的操作就可能出现问题(DOM 还没解析完成)。

<script defer src="myscript.js"></script>:有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DoMContentLoaded 事件触发之前完成,因此 defer 适合与 DOM 有关联的脚本。

注意:

  • 如果 script 无 src 属性,则 defer, async 会被忽略
  • 动态添加的 script 标签隐含 async 属性
  • 不管是 async 还是 defer,两者都只适用于外部的脚本,而且还要注意兼容性的问题,如果浏览器不能兼容,还是把 script 标签放到页面的底部比较好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值