文档、资源加载
网页生命周期
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
事件,无论是成功加载还是出现错误