比windows.onload更早执行的方法

来源:互联网 发布:游戏服务器端编程书籍 编辑:程序博客网 时间:2024/04/27 17:57

最近在学习jQuery,里面牵涉到页面的加载问题,无意中看到这篇文章,觉得很好,估计以后能够用上,特意转贴于下:

原文地址:http://www.cnblogs.com/rubylouvre/archive/2010/04/15/1712780.html

domReady第三版


新的版本放弃使用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();
        })();
      }
 <!doctype html><html lang="en">  <head>    <meta charset="utf-8" />    <meta content="IE=8" http-equiv="X-UA-Compatible"/>    <title>domReady by 司徒正美</title>    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />    <title>domReady by 司徒正美</title>       <script type="text/javascript">           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();        })();      }      window.onload = function(){        var p = document.createElement("p")        p.innerHTML = "window.onload"        document.body.appendChild(p);      };      dom.ready(function(){        var p = document.createElement("p")        p.innerHTML = "domReady1"        document.body.appendChild(p);      });      dom.ready(function(){        var p = document.createElement("p")        p.innerHTML = "domReady2"        document.body.appendChild(p);      });          </script>  </head>  <body>    <h1>domReady第三版</h1>    <p id="p"></p>    <h1>加载图片</h1>    <p><img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s011.jpg"></p>  </body></html>