HTML页面的生命周期包含以下4个事件:
DOMContentLoaded
事件:浏览器已经完全加载HTML
,并构建了DOM
树,但像<img>
和样式表之类的外部资源可能尚未加载完成。【DOM
已经就绪,因此处理程序可以查找DOM
节点,并初始化接口】load
事件:浏览器不仅加载完成了HTML
,还加载完成了所有外部资源:图片、样式等。【外部资源加载完成,样式已被应用,图片大小已知】beforeunload
事件:用户正在离开页面:我们可以检查用户是否保存了更改,并询问他是否真的要离开。unload
事件:用户几乎已经离开了,但是我们仍然可以启动一些操作,例如发送统计数据。
DOMContentLoaded和脚本
当浏览器处理一个HTML
文档,并在文档中遇到<script>
标签时,就会在继续构建DOM
之前运行它。这是一种防范措施,因为脚本可能想要修改DOM
,甚至对其执行document.write
操作,所以DOMContentLoaded
必须等待脚本执行结束后才能执行。
此规则有两个例外:
- 具有
async
特性的脚本不会阻塞DOMContentLoaded
- 使用
document.createElement('script')
动态生产并添加到网页的脚本也不会阻塞DOMContentLoaded
DOMContentLoaded和样式
外部样式表不会影响DOM,因此DOMContentLoaded不会等待它们。
但是这里有一个值得⚠️注意的点:如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成。原因是:脚本可能想要获取元素的坐标和其他与样式相关的属性,因此它必须等待样式加载完成。
(此时当DOMContentLoaded
等待脚本时,它现在也在等待脚本前面的样式)
浏览器内建的自动填充
当我们在使用浏览器访问网页时,会使用到浏览器自动填充表单的功能。自动填充表单是在DOMContentLoaded
中执行的。因此,如果DOMContentLoaded
被需要加载很长时间的脚本延迟触发,那么自动填充也会等待。
window.onload
当整个页面,包括样式、图片和其他资源被加载完成时,会触犯window
对象上的load
事件。通过load
属性获取此事件。
window.onunload
当访问者离开页面时,window
对象上的unload
事件就会被触发。我们可以在此事件上做一些不涉及延迟的操作,例如关闭相关的弹出窗口。
有一个值得注意的特殊情况是发送分析数据:
假设我们收集有关页面使用情况的数据:鼠标点击,滚动,被查看的页面区域等。自然地,当用户要离开的时候,我们希望通过 unload 事件将数据保存到我们的服务器上(该操作涉及到延迟问题)。
有一个特殊的 navigator.sendBeacon(url, data)
方法可以满足这种需求。它在后台发送数据,转换到另外一个页面不会有延迟:浏览器离开页面,但仍然在执行 sendBeacon
。当 sendBeacon
请求完成时,浏览器可能已经离开了文档,所以就无法获取服务器响应(对于分析数据来说通常为空)。还有一个 keep-alive
标志,该标志用于在 fetch
方法中为通用的网络请求执行此类“离开页面后”的请求。
如果我们要取消跳转到另一页面的操作,在这里做不到。但是我们可以使用另一个事件 —— onbeforeunload
。
window.onbeforeunload
如果访问者触发了离开页面的导航(navigation
)或试图关闭窗口,beforeunload
处理程序将要求进行更多确认。如果我们要取消事件,浏览器会询问用户是否确定。
总结:
页面的生命周期事件:
当 DOM 准备就绪时,
document
上的DOMContentLoaded
事件就会被触发。在这个阶段,我们可以将JavaScript
应用于元素。诸如<script>...</script>
或<script src="..."></script>
之类的脚本会阻塞DOMContentLoaded
,浏览器将等待它们执行结束。图片和其他资源仍然可以继续被加载。当页面和所有资源都加载完成时,
window
上的load
事件就会被触发。我们很少使用它,因为通常无需等待那么长时间。当用户想要离开页面时,
window
上的beforeunload
事件就会被触发。如果我们取消这个事件,浏览器就会询问我们是否真的要离开(例如,我们有未保存的更改)。当用户最终离开时,
window
上的unload
事件就会被触发。在处理程序中,我们只能执行不涉及延迟或询问用户的简单操作。正是由于这个限制,它很少被使用。我们可以使用navigator.sendBeacon
来发送网络请求。