页面加载时机解密:window.onload vs document.ready
⏱️ 页面加载时机解密:window.onloadvsdocument.ready
🤔 为什么需要区分加载时机?
浏览器加载一个网页,并不是“一瞬间”全部完成的,而是一个分阶段的过程:
- 解析 HTML:构建 DOM 树(文档对象模型)。
- 加载资源:下载 CSS、JS、图片、视频等外部资源。
- 渲染页面:将 DOM 和 CSSOM 结合,绘制到屏幕上。
如果在错误的时机操作 DOM(比如元素还没生成就去获取它),代码就会报错。因此,我们需要知道“什么时候可以安全地操作 DOM”以及“什么时候所有资源都准备好了”。
通俗比喻:
想象你在装修新房(加载网页):
document.ready(DOMContentLoaded):硬装结束。墙壁刷好了,地板铺好了,家具(DOM 元素)都到位了。你可以开始布置软装(绑定事件、操作 DOM),不需要等待快递(图片/视频)送达。window.onload:全屋就绪。不仅硬装好了,连网购的大冰箱、沙发、装饰画(图片、iframe 等资源)全都送货上门并摆放完毕。这时候才是真正的“完全加载”。
📂 目录
- 🛠️ 两大主角介绍
- ⚖️ 核心区别:触发时机大不同
- 💻 代码实战:一看就懂
- 🔄 现代替代方案:原生 JS 怎么做?
- ⚠️ 常见陷阱与最佳实践
- 💡 总结
1. 🛠️ 两大主角介绍
✅document.ready(jQuery 概念)
注意:$(document).ready()是 jQuery 库提供的方法。在原生 JavaScript 中,对应的事件是DOMContentLoaded。
- 含义:当初始的 HTML 文档被完全加载和解析之后触发,无需等待样式表、图像和子框架完成加载。
- 特点:速度快,通常在页面视觉呈现初期就会触发。
- 逻辑:“DOM 树建好了,我可以开始操作元素了!”
✅window.onload
- 含义:当整个页面及所有依赖资源(如图片、CSS、JS、iframe 等)都加载完毕后触发。
- 特点:速度较慢,必须等到所有资源下载完成。
- 逻辑:“所有东西都到位了,我可以开始计算图片尺寸、进行复杂布局了!”
2. ⚖️ 核心区别:触发时机大不同
| 特性 | document.ready(DOMContentLoaded) | window.onload |
|---|---|---|
| 触发时机 | DOM 解析完成后立即触发 | 所有资源(图片、样式等)加载完成后触发 |
| 等待图片? | ❌ 不等待 | ✅ 等待 |
| 执行速度 | 🚀快 | 🐢慢(取决于资源大小) |
| 适用场景 | 大多数 DOM 操作、事件绑定、初始化插件 | 需要获取图片宽高、依赖资源完全加载的场景 |
| 原生对应 | document.addEventListener('DOMContentLoaded', ...) | window.addEventListener('load', ...) |
黄金法则:
- 90% 的业务逻辑(如点击事件、表单验证、动态内容填充)应该使用
document.ready/DOMContentLoaded,因为用户体验更流畅,无需等待大图加载。- 只有当你确实需要依赖图片尺寸或外部资源完全就绪时,才使用
window.onload。
3. 💻 代码实战:一看就懂
假设我们有一个包含大图片的页面:
<imgsrc="huge-image.jpg"id="myImg"/><divid="content">Hello</div>场景一:使用document.ready(jQuery 风格)
// jQuery 写法$(document).ready(function(){console.log("DOM 准备好了!");// ✅ 可以安全获取 divconsole.log(document.getElementById("content").innerText);// ⚠️ 此时图片可能还没加载完constimg=document.getElementById("myImg");console.log(img.width);// 可能是 0,或者自然宽度,取决于浏览器实现});场景二:使用window.onload
// 原生 JS 写法window.onload=function(){console.log("所有资源加载完毕!");// ✅ 此时图片肯定加载完了constimg=document.getElementById("myImg");console.log(img.width);// 肯定是图片的真实渲染宽度};执行顺序演示
如果同时注册这两个事件,控制台输出顺序一定是:
"DOM 准备好了!"(先执行)- (等待图片下载…)
"所有资源加载完毕!"(后执行)
4. 🔄 现代替代方案:原生 JS 怎么做?
现在的项目很少强制依赖 jQuery,我们应该掌握原生的写法。
✅ 推荐:DOMContentLoaded
这是document.ready的原生等价物。
document.addEventListener("DOMContentLoaded",function(){console.log("HTML 文档已完全加载和解析");// 在这里执行你的初始化代码initApp();});✅ 备选:load事件
这是window.onload的现代写法(建议使用addEventListener而不是直接赋值window.onload,以避免覆盖其他监听器)。
window.addEventListener("load",function(){console.log("页面及其所有资源(图片、样式表等)已完全加载");// 在这里执行依赖资源的代码calculateLayout();});💡 进阶:defer属性
如果你将<script>标签放在<head>中,可以使用defer属性,它的效果类似于DOMContentLoaded,但更优雅:
<head><!-- 脚本会异步下载,但在 HTML 解析完成后、DOMContentLoaded 触发前执行 --><scriptsrc="app.js"defer></script></head>优势:无需在 JS 里写监听器,脚本自动在 DOM 就绪时执行,且保持执行顺序。
5. ⚠️ 常见陷阱与最佳实践
❌ 陷阱 1:在head中直接操作 DOM
<head><script>// ❌ 错误:此时 body 还没解析,getElementById 返回 nulldocument.getElementById("demo").innerHTML="Hello";</script></head><body><divid="demo"></div></body>✅ 修正:
- 将脚本移到
</body>之前。 - 或者使用
DOMContentLoaded监听。 - 或者给 script 添加
defer。
❌ 陷阱 2:混用window.onload赋值
// ❌ 危险:第二次赋值会覆盖第一次window.onload=functionA;window.onload=functionB;// functionA 永远不会执行!✅ 修正:始终使用addEventListener。
window.addEventListener("load",functionA);window.addEventListener("load",functionB);// 两个都会执行❌ 陷阱 3:误以为ready等待图片
很多新手以为$(document).ready()后图片就能拿到宽高,结果发现是 0。请记住:Ready 不等图片!
💡 总结
| 特性 | DOMContentLoaded(即 ready) | window.onload(即 load) |
|---|---|---|
| 核心含义 | DOM 树构建完成 | 页面所有资源加载完成 |
| 速度 | 快 | 慢 |
| 能否操作 DOM | ✅ 能 | ✅ 能 |
| 能否获取图片尺寸 | ❌ 不一定 | ✅ 能 |
| 推荐程度 | 🌟🌟🌟🌟🌟 (绝大多数场景) | 🌟🌟 (特定场景) |
🚀 博主寄语:
理解加载时机,是写出高性能、无 Bug 前端代码的基础。记住口诀:
DOM 就绪用 Ready (DOMContentLoaded),
资源全齐用 Load (onload)。
脚本放置加 Defer,
覆盖监听要避免。
希望这篇文档能帮你彻底厘清window.onload和document.ready的区别!如果有疑问,欢迎在评论区留言。👇
喜欢这篇文章吗?记得点赞、收藏、转发哦!❤️
