脚本置于body闭合标签前时,是否需用defer/async避免渲染阻塞?
关于body末尾脚本的渲染阻塞与页面绘制逻辑
Great question! This is a super common point of confusion when optimizing page performance, so let's break it down step by step:
1. 放在</body>前的脚本会造成渲染阻塞吗?
简短结论:它们会极大减少渲染阻塞的影响,但并非完全消除——原因如下:
浏览器解析HTML时,一旦碰到<script>标签(内联或外部),默认会立刻暂停当前的HTML解析流程:
- 暂停HTML解析
- 如果是外部脚本,先下载文件(现代浏览器会并行下载多个外部脚本,但执行依然是串行顺序)
- 执行完整脚本代码
- 完成后才会继续解析剩余的HTML
但因为你把脚本放在<body>的末尾,当浏览器处理到这些脚本时,页面的绝大部分DOM已经解析完成了。它们只会阻塞最后一小部分HTML(比如闭合的</body>和</html>标签)以及页面初始化的最终步骤。关键是,页面的核心内容在脚本运行前就已经完成解析并开始渲染了。
2. 页面绘制需要等整个HTML解析完成才开始吗?
完全不需要——浏览器采用渐进式渲染机制,尽可能早地把内容展示给用户:
- 浏览器会逐段解析HTML,逐步构建DOM树
- 一旦某段DOM(比如页面头部、某个段落)解析完成,就会把这部分转化为渲染树并绘制到屏幕上
- 这个过程会和剩余HTML的解析同时进行
所以当你放在<body>末尾的脚本开始运行时,页面的大部分内容已经对用户可见了。脚本可能会延迟交互元素或动态内容的加载,但不会阻塞静态内容的初始渲染。
3. 为什么Google PageSpeed还建议使用defer或async?
即使放在<body>末尾,添加这两个属性依然能带来性能提升:
defer:脚本会在后台下载,完全不阻塞HTML解析。它们会按照在HTML中的顺序,在整个DOM解析完成后、DOMContentLoaded事件触发前执行,适合依赖完整DOM或其他脚本的场景。async:脚本在后台下载,下载完成后立即执行(可能会短暂暂停HTML解析),适合不依赖DOM、也不依赖其他脚本的独立脚本(比如分析追踪工具)。
这两个属性能让浏览器更高效地利用资源,避免哪怕是最后一点点HTML解析的阻塞,进一步缩短页面整体加载时间——在脚本体积较大或网络状况不佳时,效果会更明显。
快速总结
- 放在
</body>前的脚本不会阻塞页面核心内容的初始渲染,但会阻塞HTML解析的收尾阶段和页面初始化的最终步骤 - 页面绘制是渐进式的,不需要等整个HTML文档解析完成才开始
- 给这些脚本添加
defer或async能进一步优化性能,符合PageSpeed的优化建议
内容的提问来源于stack exchange,提问作者Mayur Arora
相关产品推荐
相关产品推荐

