找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖
Claude、GPT 海外模型 API 接入Claude skills 从入门到精通 吴恩达亲授 AI Agent 核心技能2026 瞪哥公务员考试全攻略 行测申论一站式系统备考
Agent 文心智能蒸馏模型实战 90G 课程智泊 AI 大模型训练营 基于 LangChain 的 RAG 与提示工程实战构建企业级 AI 大脑:大模型微调与 RAG / Agent 全栈实战

5045

积分

0

好友

653

主题
发表于 2025-12-17 02:30:09 | 查看: 319| 回复: 0

在前端开发与性能优化的实践中,<script>标签的async和defer属性都是用于优化外部脚本加载行为、避免阻塞页面渲染的关键属性。尽管它们都能实现脚本加载与HTML解析的并行,但在执行时机、顺序保证和适用场景上存在本质区别。理解这些差异对于编写高性能、可预测的Web页面至关重要。

一、 阻塞问题:为何需要 async/defer?

在默认情况下(即<script>标签不添加任何属性),浏览器的处理流程是线性的、阻塞式的:

  1. 暂停HTML文档的解析。
  2. 开始下载<script>标签指定的外部脚本文件。
  3. 等待脚本下载完成后,立即执行。
  4. 脚本执行完毕,才恢复HTML文档的解析。

当脚本文件体积较大或网络状况不佳时,这种阻塞会显著拖慢页面的首次渲染速度,影响用户体验。async和defer属性的核心价值,就在于将脚本的下载过程与HTML解析并行化,从而减少阻塞。两者的区别在于脚本执行的时机。

二、 async 属性:异步加载,立即执行

async属性适用于那些完全独立、不依赖DOM或其他脚本的脚本,例如网站分析、广告或监控代码。

核心工作流程

  1. 并行下载:浏览器在解析HTML时遇到带async属性的<script>标签,会立即开始异步下载脚本,同时继续解析后面的HTML内容。
  2. 立即执行:一旦脚本下载完成,浏览器会立即暂停HTML解析,执行该脚本。
  3. 恢复解析:脚本执行完毕后,恢复HTML解析。

关键特性与注意事项

  • 执行顺序不固定:多个async脚本的执行顺序取决于它们的下载完成顺序。即使脚本A在HTML中位于脚本B之前,如果B先下载完,也会先执行。
  • 依赖关系无法保证:正因执行顺序不确定,async脚本之间不能存在依赖关系,否则可能导致错误。
  • 可能阻塞渲染:虽然下载不阻塞,但脚本执行时依然会阻塞HTML解析。
<!-- 即使 small.js 在 large.js 之后声明,但由于其文件小下载快,可能先执行 -->

三、 defer 属性:异步加载,延迟执行

defer属性适用于那些需要操作DOM,或依赖其他脚本的场景,例如页面初始化逻辑、基于jQuery的插件等。

核心工作流程

  1. 并行下载:与async类似,浏览器遇到defer脚本时也会并行下载,不阻塞HTML解析。
  2. 延迟执行:脚本下载完成后不会立即执行,而是被放入一个队列。
  3. 有序执行:浏览器会等待整个HTML文档解析完成(触发DOMContentLoaded事件之前),再严格按照脚本在HTML中出现的顺序依次执行所有defer脚本。

关键特性与优势

  • 执行时机确定:在所有DOM元素解析完成后才执行,确保脚本可以安全操作DOM。
  • 严格保持顺序:多个defer脚本的执行顺序与它们在HTML文档中的声明顺序完全一致,无论下载快慢。
  • 完全不阻塞渲染:从下载到执行的整个过程都不会阻塞HTML的解析与渲染。
  • 完美支持依赖:只需将依赖的脚本(如库文件)放在被依赖脚本之前声明,即可确保正确的加载顺序。
<!-- 即使 small.js 先下载完,也会等待 large.js 执行完毕后再执行 -->

四、 对比总结:async vs defer vs 默认

下表从多个维度清晰对比了三者的核心差异:

对比维度 默认脚本 (无属性) async 脚本 defer 脚本
下载是否阻塞HTML解析 是 否 否
执行是否阻塞HTML解析 是 是 (执行时阻塞) 否
执行时机 下载后立即执行 下载后立即执行 HTML解析完成后,DOMContentLoaded事件前
多个脚本的执行顺序 按HTML中顺序执行 按下载完成顺序,不保证声明顺序 严格按HTML中声明顺序执行
是否适合操作DOM 不适合(DOM可能未解析) 不适合(时机不可控) 适合 (DOM已准备就绪)
是否支持脚本间依赖 支持(按顺序) 不支持 支持 (按顺序)

五、 最佳实践与选择策略

在实际的HTML与JavaScript开发中,请遵循以下原则进行选择:

优先使用 defer

  • 脚本需要访问或操作DOM元素。
  • 脚本之间存在明确的依赖关系(例如,你的业务代码依赖于某个工具库)。
  • 脚本是页面核心功能的一部分,需要稳定的执行环境。

可以考虑使用 async

  • 脚本完全独立,不依赖任何其他资源,也不被任何脚本依赖。
  • 脚本属于非关键、不影响主体功能的第三方脚本,如数据分析、广告投放代码。

重要注意事项

  1. 仅对外部脚本有效:async和defer属性只对带有src属性的外部脚本生效,对内联脚本(``)无效。
  2. 属性冲突:如果同时指定了async和defer,现代浏览器的行为是async优先级更高,会忽略defer。
  3. 动态注入的脚本:通过JavaScript动态创建的<script>元素,其async属性默认为true。如果需要保证动态脚本的执行顺序,需显式设置为async: false。



上一篇:Linux协议栈深度解析:数据包处理核心流程与性能优化实战
下一篇:Vim命令行文本编辑快速入门:核心模式与快捷键实战指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-9-28 01:28 , Processed in 0.955657 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表