深入理解 script 标签的 async,defer 属性(同步加载,异步加载,延迟执行)
|
freeflydom
2025年11月1日 9:19
本文热度 268
|
1. 异步加载 和 延迟执行 存在的意义 : 避免影响 页面渲染/显示- 浏览器解析(渲染/显示)的 阻塞问题
- 加载和解析 顺序: 浏览器在 解析 HTML 页面代码时, 是 从上到下 依次 加载, 解析、渲染
- 阻塞 1: 外部脚本 js 文件的 加载和执行, 影响 页面渲染(显示).
- 如果 , 在
<head>中 ,用<scrip> 引用了一个 外部脚本 js 文件<script src="home.js" type="text/javascript"></script>
- 而且这个 文件很大或者有问题,需要 2 秒的加载和执行时间,那么在这个时间中, 浏览器 会停止渲染页面,页面就会是 白屏显示,什么内容 都没有),2 秒后 脚本加载和执行完成 才会继续渲染页面 ,页面才显示.
- 用户体验 差: 这个时候 用户体验就很不好,因为有几秒什么也看不见,急脾气的用户,可能会直接关闭 页面.
- 这种影响 页面解析(渲染,显示)的行为, 就是阻塞。
- 阻塞 2: 外部 css 文件的加载和执行, 影响 页面渲染(显示).
CSS 文件 也一样,因为 CSS 文件 会对DOM的 样式,布局,色彩等外观 产生影响,所以浏览器会等 CSS 文件 下载并执行完成后 继续。 为了页面的性能,要避免阻塞。
2. 同步 加载和执行 (影响 页面解析/渲染/显示)
- 示例1: 下图, 是在 淘宝网的代码中 截的图,可以看到 把很多
<script>标签 ,放在了 文档底部的位置,在 文档主体 结束标签 </body> 之前.

- 示例2: 下图,是在 MDN 网站的截图, 也有
<script>标签,被放在了 文档的底部,</body> 标签之前.

3. async 属性: 异步加载 (不是 异步执行,搭配 src 属性,仅限 外部脚本)
- 示例1: 在MDN网站的 文档头部标签
<head>中,也出现了 异步加载的 js文件 <script>
4. defer 属性: 延迟执行 (不是 延迟加载,加载是 并行的,搭配 src 属性,仅限 外部脚本 )延迟执行: defer - ① 并行获取: 如果 异步加载
async属性 不存在,而 延迟执行defer属性 存在,那么脚本将被 并行获取 - ② 延迟执行: 并在页面完成解析后 进行执行。
- 注意: 搭配
src 属性,延迟执行, 仅限 外部脚本
延迟执行 defer的 加载和执行 过程示例图 - ① 加载:是并行的,不影响 页面解析
- ② 执行: 不是并行的, 但不会打断 页面解析,因为是在 页面解析完成后 才执行的.
- 加载和执行,都不会打断 页面解析.

延迟执行的 使用时机 - 延迟执行:
- 有些
js代码 并不是 页面初始化的时候 就立刻需要的,而在 稍后的某些情况才需要的。 - 那么一开始 并不执行 这些暂时不用的
js,而是在需要的时候 或稍后 再通过js 的控制来执行,也不会影响。
根据 js 的需要时机 进行分类: - 将
js 切分成许多模块,页面初始化时 只执行 需要立即执行的 js 可以使用 同步加载 ,可以放在head的script标签中 - 其它 js ,可以延迟执行。
- 比如, 页面有大量不同的模块 组成,很多可能 暂时不用或根本就没用到。
- 就像图片的延迟加载,在图片出现在可视区域内时(在滚动条下拉)才加载显示图片.
延迟加载: 除了延迟执行,其实也可以设置 延迟加载,就是把 代码片段,写在 文档的底部,</body>的前面,这样 文档按顺序加载和解析的时候,到最后 才会加载这些代码片段. 注意: defer只是 延迟执行,并不是 延迟加载,在页面解析的同时,就并行加载了,也不会影响页面解析. 冲突事项: - 用了
defer不要使用 document.write() 方法;(为什么 ?因为涉及到 页面显示吗?延迟执行了,会影响页面显示?)
- 示例1: MDN 网站中,在 文档的 底部,
</body>之前,就添加了 延迟执行的 脚本文件.

- 示例2: 延迟加载 (无关
defer)- 如果 页面 初始的渲染, 并不依赖于
js 或者 css, 可以用 延迟加载 - 即,最后加载
js, css代码,把 引用外部文件的代码 写在最后 </body>前面。 - 比如,一些按钮的 点击事件,轮播图动画的脚本 也可以放在最后。
<html>
<head>
</head>
<body>
<script type="text/javascript" src="a.js"></script>
<link href="a.css" rel="stylesheet" />
</body>
</html>
5. 同步加载,异步加载,延迟执行的 联系和区别
⑵ 同时 指定 async,defer 属性: (行为回退,避免 阻塞行为) - 行为 回退: 即使指定了 异步加载
async属性,也可以指定 defer属性- 回退到 延迟执行: 以使 仅支持 延迟执行
defer(而不支持 异步加载async)的遗留Web浏览器 退回到 延迟执行defer行为,而不是 默认的阻塞行为。
⑶ 多个脚本的 执行顺序: - ① 同步加载
- 按顺序: 放置在
<head>内- 会阻塞
<body>的渲染, 会出现白屏,按照顺序 立即执行几个脚本文件
- ★ 按顺序: 放置在
<body>底部- 等
<body>中的内容 渲染完毕后, 再加载, 顺序执行js<script>写在<body>底部,没有 兼容性问题,没有 白屏问题,没有 执行顺序问题.
- 是比较推荐的写法,很多网站都在使用,比如 淘宝网, MDN 网站等.
- ② 异步加载: 放置在
<head>头部并使用async- 先加载完毕的 先执行: 异步 并行加载资源,且加载完JS资源立即执行,并不会按 js 文件的顺序,谁快 谁先上
- ③ 延迟执行: 放置在
<head>头部并使用defer- 按 顺序执行: 异步 并行加载资源,在 DOM 渲染后,即,页面解析完毕后, 再按顺序执行
js - HTML5 规范要求 脚本按照它们出现的 先后顺序执行,因此 第一个
defer 延迟脚本, 会先 于第二个延迟脚本执行,而这两个脚本 会先于 DOMContentLoaded 事件执行。 - 在实际应用当中,延迟执行的脚本 并不一定会按照 顺序执行,也不一定会在
DOMContentLoad 时间触发前 执行,因此最好只包含一个延迟脚本。
- ④ ★ 异步加载 和延迟执行: 放置在
<head>头部, 并同时使用async和defer- 表现和
async一致 - 不支持
async的,支持defer的,会表现得和defer一样 - 这种方法,也是比较推荐的,同时兼容 支持
async和defer 两个属性的 浏览器
⑷ 仅限 外部脚本: 脚本<script>标签的 异步加载 async和 延迟执行defer,都必须搭配 src 属性,仅限 外部脚本 使用.
- 示例1: 在 MDN 网站中,也出现了 同时设置 异步加载和延迟执行的
<script> 标签. 
转自https://blog.csdn.net/VickyTsai/article/details/102841293
该文章在 2025/11/1 9:19:48 编辑过
|
|