
在实际项目里,defer 属性的核心作用是 “既不耽误页面渲染,又能保证脚本按顺序执行”,特别适合处理那些“需要操作页面元素、或有依赖关系”的脚本,既优化了性能,又避免了功能出错。举几个常见场景你就懂了:
比如页面加载后要给按钮绑定点击事件、给列表渲染数据——这类脚本必须等HTML解析完(比如按钮、列表这些元素已经存在)才能执行,否则会报错“找不到元素”。
如果不用 defer,要么把脚本写在HTML末尾(但代码结构乱),要么用DOMContentLoaded事件(多一层嵌套);用了 defer,脚本可以放在<head>里(代码结构清晰),浏览器会一边解析HTML、一边后台加载脚本,等HTML全解析完,脚本再按顺序执行,既不阻塞渲染,又能直接操作DOM。
<head>
<!-- 初始化脚本:需要操作页面中的按钮和列表 -->
<script defer src="init-page.js"></script>
</head>
<body>
<button id="submitBtn">提交</button>
<ul id="list"></ul>
</body>init-page.js 里的代码可以直接写:
// 不用等DOMContentLoaded,因为defer确保HTML已解析完
document.getElementById('submitBtn').addEventListener('click', () => {
alert('点击成功');
});
// 渲染列表
const list = document.getElementById('list');
list.innerHTML = '<li>第一条数据</li><li>第二条数据</li>';比如项目里用了“工具库脚本(utils.js)”和“业务脚本(business.js)”,business.js 里的代码要调用 utils.js 里的函数——这时候必须保证 utils.js 先执行,business.js 后执行。
如果用 async,两个脚本谁先加载完谁先执行,很可能 business.js 先跑,导致“找不到utils函数”的错误;但用 defer,哪怕 business.js 先加载完,也会等 utils.js 执行完再跑,完美保证顺序,同时还不阻塞页面渲染。
<!-- 先加载工具库,再加载业务脚本,defer会按顺序执行 -->
<script defer src="utils.js"></script>
<script defer src="business.js"></script>utils.js 里定义工具函数:
// 工具函数:格式化时间
function formatTime(time) {
return new Date(time).toLocaleString();
}business.js 里直接用:
// 不用担心utils没加载,defer保证顺序
const now = formatTime(Date.now());
console.log('当前时间:', now); // 正常执行,不报错比如页面首屏是文章内容,底部有个“访问量统计图表”——图表脚本(比如ECharts)体积大,但用户先看的是文章,没必要让图表脚本阻塞首屏渲染。
用 defer 加载图表脚本,浏览器会在后台加载,等HTML解析完(用户已经能看文章了),再执行脚本渲染图表,既不影响首屏加载速度,又能正常显示图表。
<head>
<!-- 加载ECharts图表脚本,defer确保不阻塞首屏 -->
<script defer src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<!-- 图表初始化脚本,依赖ECharts,defer保证顺序 -->
<script defer src="chart-init.js"></script>
</head>
<body>
<!-- 首屏内容:文章 -->
<div class="article">
<h2>文章标题</h2>
<p>文章内容...</p>
</div>
<!-- 非首屏:图表容器 -->
<div id="chart" style="width: 600px; height: 400px;"></div>
</body>defer 的性能优化核心价值:<head>里,不用散落在HTML末尾,方便维护。 简单说,defer 就是给“需要等页面准备好、又有顺序要求”的脚本开了个“绿色通道”——既不拖慢页面,又能按规矩干活。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。