DOMContentLoaded
浏览器已经完全加载了HTML,DOM树已经构建完毕,但是像是 和样式表等外部资源可能并没有下载完毕。
1 | document.addEventListener("DOMContentLoaded", function() { |
DOMContentLoaded 和脚本
当浏览器在解析HTML页面时遇到了标签,将无法继续构建DOM树(译注:UI渲染线程与JS引擎是互斥的,当JS引擎执行时UI线程会被挂起),必须立即执行脚本。所以 DOMContentLoaded 有可能在所有脚本执行完毕后触发。
外部脚本(带src的)的加载和解析也会暂停DOM树构建,所以 DOMContentLoaded 也会等待外部脚本。
不过有两个例外是带async和defer的外部脚本,他们告诉浏览器继续解析而不需要等待脚本的执行,所以用户可以在脚本加载完成前可以看到页面,有较好的用户体验。
async和defer属性仅仅对外部脚本起作用,并且他们在src不存在时会被自动忽略。
它们都告诉浏览器继续处理页面上的内容,而在后台加载脚本,然后在脚本加载完毕后再执行。所以脚本不会阻塞DOM树的构建和页面的渲染。
其实这里是不对的,带有async和defer的脚本的下载是和HTML的下载与解析是异步的,但是js的执行一定是和UI线程是互斥的,像下面这张图所示,async在下载完毕后的执行会阻塞HTML的解析
两处不同
async | defer |
---|---|
带有async的脚本是优先执行先加载完的脚本,他们在页面中的顺序并不影响他们执行的顺序。 | 带有defer的脚本按照他们在页面中出现的顺序依次执行。 |
带有async的脚本也许会在页面没有完全下载完之前就加载,这种情况会在脚本很小或本缓存,并且页面很大的情况下发生。 | 带有defer的脚本会在页面加载和解析完毕后执行,刚好在 DOMContentLoaded之前执行。 |
浏览器的自动补全
Firefox, Chrome和Opera会在DOMContentLoaded执行时自动补全表单。
例如,如果页面有登录的界面,浏览器记住了该页面的用户名和密码,那么在 DOMContentLoaded运行的时候浏览器会试图自动补全表单(如果用户设置允许)。
所以如果DOMContentLoaded被一个需要长时间执行的脚本阻塞,那么自动补全也会等待。你也许见过某些网站(如果你的浏览器开启了自动补全)—— 浏览器并不会立刻补全登录项,而是等到整个页面加载完毕后才填充。这就是因为在等待DOMContentLoaded事件。
使用带async和defer的脚本的一个好处就是,他们不会阻塞DOMContentLoaded和浏览器自动补全。(译注:其实执行还是会阻塞的)
load
附加资源已经加载完毕,可以在此事件触发时获得图像的大小(如果没有被在HTML/CSS中指定)
1 | window.onload = function() { |
readyState
document.readyState
- loading 加载 - document仍在加载。
- interactive 互动 - 文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
- complete - 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
1 | function work() { |
readystatechange
每当文档的加载状态改变的时候就有一个readystatechange事件被触发,所以我们可以打印所有的状态。
1 | document.addEventListener('readystatechange', () => console.log(document.readyState)) |
unload
beforeunload
即将离开页面或者关闭窗口时
有些浏览器像Chrome和火狐会忽略返回的字符串取而代之显示浏览器自身的文本,这是为了安全考虑,来保证用户不受到错误信息的误导。
需要指出的是,许多浏览器会忽略该事件并自动关闭页面无需用户的确认。火狐浏览器在配置页面about:config设有一个dom.disable_beforeunload的开关变量用于开启这个功能。
要重新加载该网站吗?
注意:可以通过检查e.clientX、e.clientY判断用户是否点击,右上角关闭浏览器的,但是实践发现 只有 IE6,IE7,IE8 能获取得到具体数值,其他浏览器均为 undefined。要离开此网站吗?
1 | window.onbeforeunload = function (e) { |
returnValue
window.onbeforeunload
各浏览器对 onbeforeunload 事件的支持与触发条件实现有差异
兼容性
- IE、Chrome、Safari 完美支持
- Firefox 不支持文字提醒信息
- Opera 不支持
问题
- IE6,IE7 使用 onbeforeunload 遇到的bug
凡是<a>
标签 都会触发 onbeforeunload事件 包括 href=”javascript:void(0)” 这种。
在IE6,IE7 下面 点击 里面的 a 标签,蛋疼的事情就发生了。
解决方法:给这 a标签的 父级 添加 onclick=function(){return false} 即可,不过添加了这个之后 要确保 父级里面没有 input type=”checkbox” 的标签,否则会导致其无效不可点击。
判断页面是否关闭
1 | window.onbeforeunload = function(e) { |
- 思考通过用户触发onbeforeunload,滞后执行beforeloadResult,注入localStorage(如果关闭页面beforeloadResult,将不会执行),用户可以选择取消。
- 由于javascript的阻塞性质,不管我们这个setTimeout设定的时间间隔有多小(太小如0貌似不行),都要等到这个我们把这个alert关闭才会执行。如果我们时间间隔够小,那么一关闭alert就会执行了。
问题:
- onbeforeunload在刷新、关闭页面都和触发,
- 在火狐浏览器下,即使页面关闭了,也依然会执行beforeloadResult();但是并没有暂停脚本执行,没有达到理想的效果。可能是因为网页关闭的时间比 执行 beforeloadResult() 所花的时间要长的原因。
- 创建一个定时任务,这个定时任务的功能是创建另一个定时任务。
- 在另一个定时任务里,定时执行我们的beforeloadResult();这个定时任务开始计算时间的时候,就是我们确定(或取消)关闭网页的时候。
1 | window.onload = function(e) { |
before-unload
before-unload
不同的条件判断引用onbeforeunload
兼容性
- Firefox (Gecko) >= 1
- Chrome >= 1
- Internet Explorer >= 4
- Opera >= 12
- Safari (Webkit) >= 3
unload
浏览器卸载页面后执行的事件(由于种种限制,很少被使用)
1 | //JS document |
兼容性
- IE6,IE7,IE8 中 刷新页面、关闭浏览器之后、页面跳转之后都会执行;
- IE9 刷新页面 会执行,页面跳转、关闭浏览器不能执行;
- firefox(包括firefox3.6) 关闭标签之后、页面跳转之后、刷新页面之后能执行,但关闭浏览器不能执行;
- Safari 刷新页面、页面跳转之后会执行,但关闭浏览器不能执行;
- Opera、Chrome 任何情况都不执行。