大部分Web应用都需要Web浏览器通知他们文档加载完毕和为操作准备就绪的时间。Window对象的load事件就是为了这个目的。load事件直到文档和所有图片加载完毕时才发生。然而,在文档完全解析之后但在所有图片全部加载完毕之前开始运行脚本通常是安全的,所以如果基于“load”发生之前的事件触发脚本会提升Web应用的启动时间。
当文档加载解析完毕且所有延迟(deferred)脚本都执行完毕时会触发DOMContentLoaded事件,此时图片和异步(async)脚本可以依旧在加载,但是文档已经为操作准备就绪了。Firefox引入了这个事件,然后塔被包括Microsoft的IE9在内的所有其他浏览器采用。尽管其名字中有“DOM”,并属于3级DOM事件标准的一部分,但HTML5标准化了它。
document.readyState属性随着文档加载过程而变化。在IE中,每次状态改变都伴随着Document对象上的readystatechange事件,当IE接受到“complete”状态时使用这个事件来做判断是可行的。HTML5标准化了readystatechange事件,但它仅在load事件之前立即出发,所以目前尚不清楚监听“readystatechange”取代“load”会带来多大的好处。
下面定义了whenReady()函数。当文档为操作准备就绪时,传递给whenReady()的函数将会作为Document对象的方法调用。和之前的onLoad()函数不同,whenReady()监听DOMContentLoaded和readystatechange事件,而使用load事件仅仅是为了兼容那些不支持之前事件的较老的浏览器。
/*
* 传递函数给whenReady(),当文档解析完毕时且为操作准备就绪时,
* 函数将作为文档对象的方法调用
* DOMContentLoaded、readystatechange或load事件发生时会触发注册函数
* 一旦文档准备就绪,所有函数都将被调用,任何传递给whenReady()的函数都将立即调用
*/
var whenReady = (function(){
var funcs = []; // 当获得事件时,要运行的函数
var ready = false; // 当触发事件处理程序时,切换到true
// 当文档准备就绪时,调用事件处理程序
function handler(e) {
// 如果已经运行过一次,只需要返回
if (ready) return;
// 如果发生readystatechange事件,
// 但其状态不是“complete”的话,那么文档尚未准备好
if (e.type == "readystatechange" && document.readystate !="complete")
return;
// 运行所有注册函数
// 注意每次都要计算fucs.length,
// 以防这些函数的调用会导致注册更多的函数
for (var i = 0; i < funcs.length; i++) {
funcs[i].call(document);
};
// 现在设置ready标识为true,并移除所有函数
ready = true;
funcs = null;
}
// 为接受到的任何事件注册处理程序
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", handler, false);
document.addEventListener("readystatechange", handler, false);
window.addEventListener("load", handler, false);
}
else if (document.attachEvent) {
document.attachEvent("onreadystatechange", handler);
window.attachEvent("onload", handler);
};
// 返回whenReady函数
return function whenReady(f) {
if (ready) f.call(document);
else funcs.push(f);
}
}());
备注:该函数与jQuery中的$(document).ready()不同,只有当DOM解析完毕并且图片等资源加载完后,才执行传入whenReady()的函数。