html defer延迟加载脚本
用 defer 优雅地掌控页面脚本加载的节奏
在网页加载的“交响乐”里,脚本加载往往是一把双刃剑。如果它来得太早,会在页面渲染前抢走资源,让布局迟迟不见;如果太晚,又会让功能初始化延迟,体验打折扣。用好 HTML 的 <script> 元素与 defer 属性,能让人与机器的节奏更默契一些。
为什么 defer 重要
简单说,defer 把脚本的执行放到文档解析完成后、但在页面渲染之前进行。这意味着它不阻塞 HTML 解析,也不同于 async 的“先执行后解析”,更不如同位的内联脚本在渲染前就插入执行。
在真实场景里,比如加载一个统计模块或第三方组件,把它的加载改为 defer,通常能明显减少首次可交互时间(FOIT)与感知延迟,页面会更顺滑。
基本用法与核心差异
<script src="/path/to/script.js" defer></script>
在多个脚本并存时,浏览器会按文档中出现的顺序执行 defer 脚本;若同时出现 async 与 defer,它们会被分别处理:async 一旦下载即执行,可能中断页面渲染;defer 被统一收集,待解析完成后再按顺序执行。
实战场景:组件与统计模块
设想你在加载页面时需要初始化一个组件库与一个统计模块。把它们放到 defer 集合里,能避免阻塞解析,又能保证初始化在渲染前完成。
<!-- 主要渲染资源 -->
<div id="app"></div>
<script src="/bundle.js" defer></script>
<!-- 统计模块,按需加载 -->
<script src="/analytics.js" defer></script>
<!-- 组件库初始化 -->
<script src="/components.js" defer></script>
进阶:动态脚本与 defer
当需要动态创建脚本时,也可以使用 defer,但要注意执行顺序。
const script = document.createElement('script');
script.src = '/dynamic-script.js';
script.defer = true;
document.head.appendChild(script);
如果依赖顺序严格,可用 Promise 模拟依赖注入:
Promise.all([
new Promise(resolve => {
const s = document.createElement('script');
s.src = '/depend1.js';
s.defer = true;
s.onload = resolve;
document.head.appendChild(s);
}),
new Promise(resolve => {
const s = document.createElement('script');
s.src = '/depend2.js';
s.defer = true;
s.onload = resolve;
document.head.appendChild(s);
})
]).then(() => {
console.log('依赖加载就绪,可安全初始化主脚本');
});
避坑指南:常见误解与注意点
- 不把 defer 作为“无条件的晚执行”:某些初始化必须在渲染前完成,过晚可能导致布局抖动或交互延迟。
- 避免在 defer 脚本中进行长时间同步操作,否则会拖慢后续脚本执行与页面渲染。
- 对于必须在解析阶段就能运行的脚本(如定义立即使用的全局变量),尽量不要使用 defer。
结语
用好 defer,就是在页面加载与脚本执行之间找到合适的节拍。它不是万能的,但能显著减少不必要的阻塞,提升页面的首屏体验与可感知性能。在模块化与组件化日益复杂的今天,掌握这一技巧,能让你的页面更轻、更稳、更友好。


还没有评论,来说两句吧...