Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

我的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();
        })();
      }
   

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(5509)  评论(11编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示