文档、资源加载
网页生命周期
DOMContentLoaded
浏览器已完全加载 HTML,并构建了 DOM 树,但像
<img>和样式表之类的外部资源可能尚未加载完成
DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口
<script>...<script>或<script src="..."><script>之类的脚本会阻塞DOMContentLoaded,浏览器将等待它们执行结束不会阻塞
DOMContentLoaded的脚本- 具有
async特性(attribute)的脚本不会阻塞DOMContentLoaded - 使用
document.createElement('script')动态生成并添加到网页的脚本也不会阻塞DOMContentLoade
- 具有
document.addEventListener('DOMContentLoaded', function(){
console.log('DOMContentLoaded')
})load
浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等
- 外部资源已加载完成,样式已被应用,图片大小也已知
window.onload = function(){
console.log('loaded')
}beforeunload
触发了离开页面的导航(navigation)或试图关闭窗口,
beforeunload处理程序将要求进行更多确认
- 可以检查用户是否保存了更改,并询问他是否真的要离开
window.onbeforeunload = function() {
return false;
}
window.addEventListener("beforeunload", (event) => {
// 起作用,与在 window.onbeforeunload 中 return 值的效果是一样的
event.returnValue = "有未保存的值。确认要离开吗?";
})unload
用户几乎已经离开
- 以启动一些操作,例如发送统计数据(可以使用
navigator.sendBeacon来发送网络请求)
let analyticsData = { /* 带有收集的数据的对象 */ };
window.addEventListener("unload", function() {
navigator.sendBeacon("/analytics", JSON.stringify(analyticsData));
})加载状态
readyState
document.readyState:当前加载状态信息,值情况如下:
loading:文档正在被加载interactive:文档已被解析完成,与DOMContentLoaded几乎同时发生,但是在DOMContentLoaded之前发生complete:文档和资源均已加载完成,与window.onload几乎同时发生,但是在window.onload之前发生
readystatechange
在加载状态发生改变时触发
- 在
DOMContentLoaded之前,document.readyState会立即变成interactive,所以在加载状态改变监听中打印不出loading
document.addEventListener('readystatechange', function() {
console.log('readyState:' + document.readyState)
})脚本
- 当浏览器加载 HTML 时遇到
<script>...</script>标签,浏览器就不能继续构建 DOM。它必须立刻执行此脚本。对于外部脚本<script src="..."></script>也是一样的:浏览器必须等脚本下载完,并执行结束,之后才能继续处理剩余的页面- 脚本不能访问到位于它们下面的 DOM 元素,因此,脚本无法给它们添加处理程序等
- 如果页面顶部有一个笨重的脚本,它会“阻塞页面”。在该脚本下载并执行结束前,用户都不能看到页面内容,可以把脚本放在页面底部。此时,它可以访问到它上面的元素,并且不会阻塞页面显示内容
defer
告诉浏览器不要等待脚本
浏览器将继续处理 HTML,构建 DOM
脚本会“在后台”下载,然后等 DOM 构建完成后,脚本才会执行、
仅适用于外部脚本,如果
<script>脚本没有src属性,则会忽略defer属性页面内容不受阻塞,会立即显示
DOMContentLoaded事件处理程序在具有defer特性的脚本下载且执行结束后才会被触发具有
defer特性的脚本保持其相对顺序,就像常规脚本一样- 多个
defer脚本时,同时下载,但是按照相对顺序执行
- 多个
async
与
defer有些类似。它也能够让脚本不阻塞页面。但是,在行为上二者有着重要的区别
async特性意味着脚本是 完全独立 的
仅适用于外部脚本,如果
<script>脚本没有src属性,则会忽略defer属性浏览器不会因
async脚本而阻塞(与defer类似)其他脚本不会等待
async脚本加载完成,同样,async脚本也不会等待其他脚本DOMContentLoaded和异步脚本不会彼此等待
动态脚本
使用 JavaScript 动态地创建一个脚本,并将其附加到文档中
- 当脚本被附加到文档时,脚本就会立即开始加载
- 默认情况下,动态脚本的行为是 异步 的
- 不会等待任何东西,也没有什么东西会等它们
- 先加载完成的脚本先执行
- 如果显式地设置了
script.async = false,脚本将按照脚本在文档中的顺序执行,就像defer那样
let script = document.createElement('script');
script.src = "test.js";
document.body.append(script);资源加载
浏览器允许我们跟踪外部资源的加载,如脚本、iframe、图片等,基本上适用于具有外部
src的任何资源
事件
onload:资源加载成功onerror:资源加载出现错误- 无法获取更多 HTTP error 的详细信息,不知道 error 原因,只知道是加载失败了
- 在脚本处理和执行期间可能发生的 error 超出了这些事件跟踪的范围
- 也就是说:如果脚本成功加载,则即使脚本中有编程
error,也会触发onload事件 - 如果要跟踪脚本
error,可以使用window.onerror全局处理程序
- 也就是说:如果脚本成功加载,则即使脚本中有编程
注意
大多数资源在被添加到文档中后便开始加载,但是
<img>要等到获得src后才开始加载<iframe>加载完成时会触发iframe.onload事件,无论是成功加载还是出现错误