说起“生命周期”,你可能第一反应是 Vue、React 这样的前端框架。但你有没有想过:HTML 页面,其实也有自己的生命周期!
虽然 HTML 本身没有框架那样的生命周期钩子,但浏览器在加载、解析、渲染、交互、关闭整个页面过程中,其实经历了一整套完整的流程,而且我们可以通过一些原生事件精确监听这些“节点”。
今天就来拆解一下:HTML 的生命周期,到底是怎么回事?
1. HTML 的“出生”:从请求到解析
当用户在地址栏输入一个 URL 或点击一个链接,浏览器会向服务器发送 HTTP 请求。服务器返回 HTML 文件后,浏览器开始执行 从头到尾的读取和解析。
这个阶段包含:
- DNS 解析
- TCP 连接
- 发送请求
- 接收 HTML 响应
- 开始解析 HTML
生命周期阶段名词对应:
HTML载入开始 ≈ HTML生命周期的诞生
2. 解析+构建阶段:DOM 树和 CSSOM 树的建立
HTML 不是直接显示在页面上的,它会被浏览器解析成一个结构化的 DOM 树(文档对象模型),这个过程叫做“构建 DOM”。
- HTML 标签被逐个读取
- 标签转换为 DOM 节点
- 遇到
<script>
标签可能会阻塞解析(除非加了defer
或async
)
与此同时,CSS 也被解析并构建成 CSSOM 树。
等到 DOM 和 CSSOM 都准备好后,合成一棵叫 Render Tree 的渲染树,准备开始绘制。
生命周期事件:DOMContentLoaded
document.addEventListener("DOMContentLoaded", function () {
console.log("DOM 已构建完成(不等样式图像)");
});
这个事件表示:HTML 已经完全解析完毕,DOM 树构建完成,但此时图片、样式表等静态资源可能还没加载完。
3. 页面渲染阶段:可视化生命周期
这时页面进入了“可视化”生命周期:
- 布局(Layout):计算每个元素的位置和尺寸
- 绘制(Paint):把每个节点变成像素
- 合成(Composite):最终绘制到屏幕上
这一阶段就像 HTML 的“成长”阶段:从代码变成真实可见的页面。
生命周期事件:window.onload
window.onload = function () {
console.log("页面所有资源加载完毕(包括图片、样式等)");
};
这个事件意味着:整个页面,包括所有静态资源都已加载完成。
4. 交互阶段:事件绑定、脚本执行
当页面渲染完毕,用户开始滚动、点击、输入,这时页面进入了一个相对“稳定但活跃”的阶段。
JS 脚本也在这个时候开始大量运行,比如:
- 加载动态数据(AJAX)
- 动画/滚动监听
- 表单校验
- 用户交互反馈
这个阶段,就是 HTML 生命周期中的“成熟期”。
5. 页面卸载:生命周期的终结
当用户关闭标签页、刷新页面或跳转到其他链接,页面就会被卸载。
生命周期事件: beforeunload 和 unload
window.addEventListener("beforeunload", function (e) {
e.preventDefault(); // 有些浏览器需要显式调用
e.returnValue = "确定离开吗?"; // 显示提示(部分浏览器支持)
});
beforeunload
:页面即将离开时触发,可用来做离开确认、保存状态。unload
:页面已经要离开,不能再交互,适合做一些清理动作。
window.addEventListener("unload", function () {
console.log("页面即将卸载,可做清理工作");
});
小结
阶段 | 描述 | 可用事件 |
---|---|---|
加载开始 | 开始解析 HTML 文件 | — |
DOM 构建 | DOM 树生成完成 | DOMContentLoaded |
渲染完成 | 所有资源加载完毕,页面可见 | load (即 window.onload ) |
交互中 | 脚本运行、用户交互 | 所有 JS 事件监听 |
即将卸载 | 离开当前页面 | beforeunload |
卸载完成 | 页面销毁,释放内存 | unload |
- 使用
DOMContentLoaded
来初始化依赖 DOM 的脚本(如:绑定按钮事件) - 使用
window.onload
来初始化依赖图片或其他资源的逻辑 - 避免在
unload
做太多事情,现代浏览器可能不会等你处理完 - 不推荐频繁使用
beforeunload
弹窗提示,用户体验较差