async vs defer 的区别

简介: 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 标签放到页面的底部比较好。

目录
相关文章
|
JavaScript
vue监听dom元素的宽高变化和自定义指令监听dom元素的宽高变化
vue监听dom元素的宽高变化和自定义指令监听dom元素的宽高变化
1303 0
|
7月前
|
监控 Linux iOS开发
告别数据丢失!跨平台同步工具FreeFileSync 14.2下载教程|手把手配置多设备备份
FreeFileSync 14.2 是一款开源跨平台文件同步工具,支持 Windows、macOS 和 Linux 系统。新增功能包括实时同步监控、云存储集成(Google Drive 和 Dropbox)、智能冲突解决及性能优化,适用于数据备份、服务器文件同步等场景。本文详细介绍其下载、安装、配置及高级使用技巧,并提供常见问题解答和延伸学习资源。
|
7月前
|
JSON API 数据安全/隐私保护
1688 商品详情API接口(1688API 系列)
1688 商品详情 API 接口是电商应用开发中的关键工具,尤其适用于整合 1688 平台的商品数据。该接口提供商品的基础属性、价格、库存、图片、描述及商家信息等多维度数据,支持 HTTP GET 和 POST 请求方式。通过必填的商品 ID 及可选的语言参数等,开发者能精准获取并展示商品详情,提升用户体验和决策效率。响应数据包括商品名称、类目、品牌、价格区间、库存、图片列表、详细描述及商家信息等,帮助技术员高效集成接口,实现与 1688 平台的无缝对接。供稿者:Taobaoapi2014。
|
12月前
|
缓存 UED
|
API 持续交付 开发工具
2024年开发者工具箱:提升生产力的十大利器
本文介绍了2024年最值得关注的十大开发工具,包括Visual Studio Code、Git、Docker等,涵盖代码编辑、版本控制、容器化技术、API开发、自动化部署、团队协作等多个方面,旨在帮助开发者提升工作效率和代码质量。选择合适的工具对提升开发效率至关重要,希望本文能助你一臂之力。注:工具介绍基于2024年技术和市场情况。
|
JSON JavaScript 前端开发
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
630 1
|
JavaScript
【TS】You are currently running a version of TypeScript which is not officially supported by @typesc
【TS】You are currently running a version of TypeScript which is not officially supported by @typesc
428 2
|
监控 前端开发 搜索推荐
前端埋点
前端埋点
691 1
前端埋点
|
JavaScript 前端开发 安全