我的domReady第三版

时间:2023-02-25 10:10:07

新的版本放弃使用document.write()(实际上我们依赖的是script标签的defer触发机制),主要基于如下几个理由:

  1. XHTML不支持document.write
  2. 当页面上的资源非常少时,会晚于window.onload
  3. document.write有时会覆写我们原有的DOM
  4. document.write生成的script不能通过内部函数移除

外国javascript高手Diego Perini于是发掘了doScroll这个方法。在IE下,doScroll方法存在于所有标签。但我搞来搞去,发现光是doScroll也不行,时不时就发现window.onload执行于domReady之前。只有结合onreadystatechange与doScroll这两个方法,我们才能在IE中搞出与标准浏览器相同的结果。因此你在jQuery,Prototype,swfobject,Ext等类库看到它们共同出现。而onreadystatechange其实也有些问题的,具体自己可能google一下,因此2006年左右实现domReady的代码基本依仗于document.write()。嗯,剩下的我就在代码间的注释中说明吧,这样更一目了解。

 
/*
take from dom library version 1.0, inspired by jQuery
Copyright 2010-2011 (2011.2.27更新)
Dual licensed under the MIT or GPL Version 2 licenses.
author "司徒正美"
http://www.cnblogs.com/rubylouvre/
*/

var dom = [];
//用于判定页面是否加载完毕
dom.isReady = false;
//用于添加要执行的函数
dom.ready = function(fn){
if ( dom.isReady ) {
fn()
} else {
dom.push( fn );
}
}
//执行所有在window.onload之前放入的函数
dom.fireReady = function() {
if ( !dom.isReady ) {
if ( !document.body ) {
return setTimeout( dom.fireReady, 16 );
}
dom.isReady = 1;
if ( dom.length ) {
for(var i = 0, fn;fn = dom[i];i++)
fn()
}
}
}
//开始初始化domReady函数,判定页面的加载情况
if ( document.readyState === "complete" ) {
dom.fireReady();
}else if(-[1,] ){
document.addEventListener( "DOMContentLoaded", function() {
document.removeEventListener( "DOMContentLoaded", arguments.callee , false );
dom.fireReady();
}, false );
}else {
//当页面包含图片时,onreadystatechange事件会触发在window.onload之后,
//换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时
document.attachEvent("onreadystatechange", function() {
if ( document.readyState == "complete" ) {
document.detachEvent("onreadystatechange", arguments.callee );
dom.fireReady();
}
});
(function(){
if ( dom.isReady ) {
return;
}
//doScroll存在于所有标签而不管其是否支持滚动条
//这里如果用document.documentElement.doScroll(),我们需要判定其是否位于顶层document
var node = new Image
try {
node.doScroll();
node = null//防止IE内存泄漏
} catch( e ) {
//javascrpt最短时钟间隔为16ms,这里取其倍数
//http://blog.csdn.net/aimingoo/archive/2006/12/21/1451556.aspx
setTimeout( arguments.callee, 64 );
return;
}
dom.fireReady();
})();
}