八月
08

JavaScript页面文档初始化 window.onload的替代办法

很早,大概去年就在mg12的博客看到他一篇很久以前的文章《 JavaScript 初始化装载方法 》,当时也没注意。这两天在做页面一些部分的延迟加载时,又想起了这个,因为使用window.onload,实在是一个很不明智的选择,很可能一个坏掉的图片或什么的就会导致你的JS迟迟装载不了,无法执行。

我试用了一下mg12文章中的方法,发现一个严重的错误,那就是在IE下如果同时绑定多个函数,那么就只会有最后一个执行。仔细分析了一下,原来是因为代码中判断IE页面文档初始化完毕时会向页面中写入一个

   1: <script id="__ie_onload" defer src="javascript:void(0)"></script>

而绑定多个函数时,就会向页面中写入多个上面的标签,由于页面上只允许一个id存在,所以通过document.getElementById(“__ie_onload”);自然就只能获得一个对象,所以只会执行一个绑定函数了。

我对其稍微进行了改造,无非就是加个数值变量,每次写入时让ID不同。

   1: var _flag=1;//标志整型变量
   2: function documentReady(fun){
   3:     if (document.addEventListener) {
   4:         document.addEventListener("DOMContentLoaded", fun, false);
   5:     } else if (/MSIE/i.test(navigator.userAgent)) {
   6:         document.write('<script id=__ie_onload'+_flag+' defer src=//0><\/script>');
   7:         var script = document.getElementById("__ie_onload"+_flag);_flag++;
   8:         script.onreadystatechange = function() {
   9:             if (this.readyState == 'complete') {
  10:                 fun();
  11:             }
  12:         }
  13:     } else if (/WebKit/i.test(navigator.userAgent)) {
  14:         var _timer = setInterval( function() {
  15:             if (/loaded|complete/.test(document.readyState)) {
  16:                 clearInterval(_timer);
  17:                 fun();
  18:             }
  19:         }, 10);
  20:     }
  21: }

这样如果绑定多个函数,就会在页面上依次写入id=”__ie_onload1”、id=”__ie_onload2”。。。等<script>标签了。

如此一来,即使绑定多个函数也可以顺利执行了。

后话:今天闲暇时,又上网搜了一下这方面的东西,发现早在06年就有人贴出了几近完美的解决方法,而且他们也考虑到了多个事件函数执行的问题,通过栈结构解决的。它是将绑定的所有函数存入一个栈中,判断文档下载完成后,再从栈中依次取出函数执行,相比于我上面的方法,判断文档是否完成只需要一次即可,无论绑定了多少个函数都是只需一次,而我的就需要多次了。看样子mg12看的书貌似是抄袭人家的,也不知为何进行了精简,结果还给精简错了,囧。。原始网页在http://www.thefutureoftheweb.com/blog/adddomloadevent,有兴趣围观。

下面是文章的代码去掉注释后

   1: addDOMLoadEvent = (function(){
   2:     var load_events = [],load_timer,script,done,exec,old_onload,
   3:         init = function () {
   4:             done = true;
   5:             clearInterval(load_timer);
   6:             while (exec = load_events.shift())
   7:                 exec();
   8:             if (script) script.onreadystatechange = '';
   9:         };
  10:     return function (func) {
  11:         // if the init function was already ran, just run this function now and stop
  12:         if (done) return func();
  13:         if (!load_events[0]) {
  14:             // for Mozilla/Opera9
  15:             if (document.addEventListener)
  16:                 document.addEventListener("DOMContentLoaded", init, false);
  17:             // for Internet Explorer
  18:             /*@cc_on @*/
  19:             /*@if (@_win32)*/
  20:             if (/MSIE/i.test(navigator.userAgent)){
  21:                 document.write("<script id=__ie_onload defer src=//0><\/scr"+"ipt>");
  22:                 script = document.getElementById("__ie_onload");
  23:                 script.onreadystatechange = function() {
  24:                     if (this.readyState == "complete")
  25:                         init(); // call the onload handler
  26:                 };
  27:             }
  28:             /*@end @*/
  29:             // for Safari
  30:             if (/WebKit/i.test(navigator.userAgent)) { // sniff
  31:                 load_timer = setInterval(function() {
  32:                     if (/loaded|complete/.test(document.readyState))
  33:                         init(); // call the onload handler
  34:                 }, 10);
  35:             }
  36:             old_onload = window.onload;
  37:             window.onload = function() {
  38:                 init();
  39:                 if (old_onload) old_onload();
  40:             };
  41:         }
  42:         load_events.push(func);
  43:     }
  44: })();

具体的效果,可以到我的友情链接页面查看。这个页面有许多favicon图标需要从不同的地址下载,需要时间较长,而使用本文中的初始化装载方法后,并不会因为图标的未下载而影响我js代码的执行。大家可以很顺利的看到边栏各个栏目被加载上(:边栏应用了延迟加载)。

12

本文标签: , , , ,

分享

本文短网址: http://qiqi.boy.im/6t

这篇文章已经有 55 条评论

Comments (54) Trackbacks (1)
You can leave a response or Trackback this entry .
  1. winy -#1

    比你快sf

  2. winy -#2

    果然不是很懂, :roll:
    看了这个突然想到另外一个问题,如果我在顶部载入JQuery,jQuery(document).ready(function($)是不是立即执行的呢,一些特效感觉好像快一些

    • QiQiBoY --#1

      @winy
      .ready()是jQuery封装的文档初始化函数,和文中的方法应该是差不多的,反正也不会因为图片什么的的未加载而影响相关代码执行。。。。

    • winy --#2

      @QiQiBoY 那我还是老老实实用jQuery吧,没空系统学原生的js

    • QiQiBoY --#3

      @winy
      毛主席说过,啥时候开始学习也不晚。。 :mad:

    • liuqiqi --#4

      @winy
      额。。看明白你意思了。。你想特效生效快些,就不要用$(document).ready(),直接将要执行的代码写在页面里,那样这段代码被浏览器下载后就会立即执行了

    • winy --#5

      @liuqiqi 是啊,js放底部据说可以加快速度,不过我感觉放前面效果还好些,看上去比较快生效,虽然实际载入速度都一样

    • QiQiBoY --#6

      @winy
      放在head里,页面中间一些依赖jQuery并且不需要$(document).ready()的响应会立即执行,放在底部的话,你页面中所有依赖jQuery的代码就都必须window.onload执行了,否则会报错,因为jQuery还未加载。

  3. 自由人 -#3

    :???: 不懂JS哎。。。现在从做那个东西从前台HTML到后台数据库都要我搞,真头疼。。。

  4. Page -#4

    这个很不错 我的真是图片多了别的也出不来

  5. MOPVHS -#5

    QiQiBoY是算法帝….

  6. 流年 -#6

    JQ在这方面做得很好;不过方法是需要学习的

  7. mice -#7

    我表示侧边栏延迟了以后….一直加载中

    • QiQiBoY --#1

      @mice
      我表示你在使用IE7.。

    • mice --#2

      @QiQiBoY
      我表示我是IE8= =…

    • QiQiBoY --#3

      @mice
      我表示你在使用IE7兼容模式。。。
      不过目前问题已经解决了,你可以再试一下

    • mice --#4

      @QiQiBoY
      我表示还是一直在加载..但是点more 就可以加载出来后面的=.= :twisted:

    • QiQiBoY --#5

      @mice
      怎么可能。。已经好了呀。。你刷新浏览器了吗?
      只有recent post这个栏目加载不了吧?
      之前是这样。。但是我已经处理好了呀。。。我这边测试没问题。。。win7系统+IE7(IE8的兼容模式)

    • mice --#6

      @QiQiBoY
      我表示这条信息没收到邮件 :twisted:

    • QiQiBoY --#7

      @mice
      你刷新浏览器试试看还有问题没?
      还是不能加载的话请告诉我你的操作系统。 :mad:

    • mice --#8

      @QiQiBoY
      现在OK了 :cool: 嘿嘿 效果灰常帅气哇

    • QiQiBoY --#9

      @mice
      额。。那就好。。

    • QiQiBoY --#10

      @mice
      呵呵。当然收不到了。。对第五层的所有回复,表面上是在回复你点击的那个人,而事实上你都是在回复第四层的评论者。。
      在这里第四层的评论者是我了,所以即使发邮件也是发给我了。。

    • QiQiBoY --#11

      @mice
      侧边栏即时回复测试。。能收到邮件的话请来告知一声。。

    • mice --#12

      @QiQiBoY
      我勒个去- -.我成试验品了..大半夜的..不睡觉哇- -….

      我表示我收到了..

    • QiQiBoY --#13

      @mice
      额。。。。因为你人品好。。。O(∩_∩)O~

  8. zwwooooo -#8

    js一窍不通……所以也就没用这个

  9. Bee君 -#9

    这个真的看不懂了.( ̄▽ ̄”)

  10. 海天 -#10

    貌似这段代码很强悍的啊
    下次试试

  11. aisinvon -#11

    博客效果越练越炫啦哈

  12. 阿七 -#12

    嗯,这个效果不错,不过我建议将这些ico缓存了比较好。

  13. 学夫子 -#13

    你的嵌套评论看起来太乱了,不爽啊,呵呵。文中的这个功能确实很实用,给那些着急的人一点缓冲时间

    • QiQiBoY --#1

      @学夫子
      主题私用,我自己看着爽就好。。
      另外文章中讲的不是给着急的人增加缓冲时间,而是减少着急人的缓冲时间

  14. 学夫子 -#14

    你和我理解上有误差,哈哈

  15. 小邪 -#15

    addDOMLoadEvent 这个东西是不是加到js文件里面就好,不用对后面要执行的函数做修改?

    • liuqiqi --#1

      @小邪
      addDOMLoadEvent这个你可以当成个函数,需要在页面装载完成后才执行的函数就使用addDOMLoadEvent,比如调用名为func的函数,addDOMLoadEvent(func)或addDOMLoadEvent(function(){func(arg1,arg2)}{})
      前者是调用无参数函数,后者是调用带参数函数,函数func有参数时使用后者调用方法

    • 小邪 --#2

      @liuqiqi
      喔喔,是这样啊 ~
      addDOMLoadEvent(function(){func(arg1,arg2)}{})
      终于茅厕顿开鸟 ~ 哦吼吼 ~

    • Godspeed --#3

      @liuqiqi
      你好,小邢,我不明白一个地方,你说用:addDOMLoadEvent()函数加载带参数的函数的时候是这样的:addDOMLoadEvent(function(){func(arg1,arg2)}{}) 最后面的”{}”是怎么回事啊?为什么还要写一个空花括号啊?

      如果其他人知道的话,希望也帮忙解释一下,我是个菜鸟。

    • QiQiBoY --#4

      @Godspeed
      如果func函数前面已经定义过了,那个花括号就不需要了;如果没,花括号就是表示省略掉的func的函数体部分。。

    • Godspeed --#5

      @QiQiBoY
      哦,知道了,你的意思是函数还可以在调用addDOMLoadEvent()时现定义。。

      但是我还有个小疑问,您看下小邢写的格式,正常函数定义格式不是这样吗:
      func(arg1,arg2){//xxxxx} 一对花括号是紧跟着圆括号的。

      但是小邢写的是:function(){ func(arg1,arg2) } {} 这个样的。。

      他把func函数的花括号写在了另一个函数的花括号外面。。我就不理解了。。

      是不是应该是:function(){ func(arg1,arg2) {} } 这样的啊?

      麻烦QiQiBoY再看一下,谢谢了先!

    • QiQiBoY --#6

      @Godspeed
      呵呵。。嗯,估计是手误导致的。。

    • Godspeed --#7

      @QiQiBoY
      恩,那我就懂了,刚学不久,所以对一些细节比较在意,我也挺喜欢这个加载函数的,所以就看了看。。结果就看到了小邢说的使用方法,才感到迷惑的,现在好了,豁然开朗,哈哈,以后还会常来的。。 :razz:

  1. Hello WordPress!

    [...] 2010.08 我继续折腾,期间我修改trackback样式,统一评论外观,也分享了这个修改中的一些涉及到的代码补充《修改trackback样式,统一评论外观》中代码。这期间,我对ajax兴趣逐渐浓厚起来,所以便有了这个博客加入若干Ajax效果。在折腾ajax、延迟加载中,我遇到了页面文档初始化的一些问题,于是查阅文档便有了这篇JavaScript页面文档初始化 window.onload的替代办法;后来,我有了在侧边栏开发ajax即时评论的想法,于是便出现了【效果测试展示篇】Ajax版即时侧边栏评论回复功能,掉了几天大家的胃口,然后又简单的蜻蜓点水般【原理指导篇】无时不在的评论 侧边栏即时回复功能。八月份期间,我的SimPaled主题基本上成型了,于是我将它介绍了给大家【SimPaled篇】Introduce My Blog Theme For You。很哟意思的是,我看到了腾讯微博的头像悬浮显示,于是便仿了下来仿腾讯微博式访客信息悬浮显示(JavaScript & ajax)。基于边栏评论,为了方便大家,我开发了插件发布:边栏最新评论及ajax回复——WP RC Reply AJAX。后来发现wordpress的无限嵌套的邮件回复有问题,于是有了完美解决wordpress无限嵌套<二> 【邮件发送相关问题】。因为SimPaled主题用到了很多延迟加载,所以有同学问我延迟加载怎样实现,于是我分享了自己当时的思路JS延迟加载机制函数(Lazyload)。八月份最后一件事大概要算我在博客中曝光了中文spam里的那些极品好玩的spam吧围观wordpress中文圈内好玩的spam [...]

Leave a Reply

Hi , say something.

  • :?:
  • :razz:
  • :sad:
  • :evil:
  • :!:
  • :smile:
  • :oops:
  • :grin:
  • :eek:
  • :shock:
  • :???:
  • :cool:
  • :lol:
  • :mad:
  • :twisted:
  • :roll:
  • :wink:
  • :idea:
  • :arrow:
  • :neutral:
  • :cry:
  • :mrgreen: