“DOM ready事件绑定” 在 “异步加载” 中暴露的问题及解决方案(精华帖)

“DOM ready事件绑定” 在 “异步加载” 中暴露的问题及解决方案(精华帖)

DOM ready:

DOM ready(也称document ready),是一个被广泛用于代替window.onload的事件(准确的讲是一种状态)。对其不是很熟悉的朋友可以

看这里:比window.onload更好的方式(document ready)

在异步加载中的问题:

当一个绑定了DOM ready事件的脚本(绑定方式可参见:window.onload更好的方式(document ready) )采用异步的方式加载(相关链

接:异步加 载JS的五种方式(详解) )时,会发生这样的问题:脚本加载完成时,DOM ready事件已经触发过了,这就意味着这个脚本将不

会被执行。这个问题非常棘手,也很容易碰到,那么如何解决呢?你一定会想到,在脚本中加上这样的逻辑“如果DOM ready已经触发,那么

直接执行脚本,如果尚未触发,则向DOM ready事件绑定该脚本”。没错,这样一来这个问题就可以被解决了,但是还有新的问题,那就是如

何知道DOM ready事件已经触发了呢?jQuery则回避了这个问题,它采用了这种方式:做一个双重保险,如果DOM ready错过了那就退而使

用document.readyState == "complete"来作为脚本执行的时间起点。但这种方式显然大打折扣了(因为document.readyState ="complete"

的触发时间几乎和window.onload同时,当页面中有大量图片资源时问题就非常严重了。关于这些事件的触发时间对比,可见:window.onl -

-oad 好的方式(document  ready) )。

更好的方法:

首先我们来分析一下各个浏览器的特性,在Firefox和Chrome中document.readyState值为interactive时DOM树就已经ready了,而IE不会出现

前面所讲的问题(因为我们是使用document.documentElement.doScroll来定时检测的),在Opera下document.readyState=="complete"和

DOM ready几乎是同时触发的(因此可以直接用document.readyState=="complete"来判断)。有了这些特性,这个问题就迎刃而解了(详

细请看下面的代码)。

Javascript代码:

(function(d, f){

        if(window.attachEvent){

                (function(){

                        try{

                                d.documentElement.doScroll("left");

                        }catch(err){

                                setTimeout(arguments.callee, 1);

                                return;

                        }

                        f();

                })();

        }else{

                if((d.readyState == "interactive") && (!!alert) || (d.readyState == "complete")){

                        f();

                }else{

                        function _f(){

                                d.removeEventListener("DOMContentLoaded", _f, false);

                                f();

                        }

                        d.addEventListener("DOMContentLoaded", _f, false);

                }

        }

})(document, main);

代码讲解:

1. 在Firefox和Chrome中,document.readyState=="interactive"时就已经DOM ready了。

2. 在IE中,在DOM ready之前调用document.documentElement.doScroll("left")都会报错,因此使用循环和try...catch来捕捉DOM ready。

3. 在Opera中,document.readyState=="interactive"时alert是不可访问的,因此!!alert将返回false。

4. main是我们所要向DOM ready绑定的函数。

注意事项:

document.readyState == "interactive" 是在DOMContentLoaded事件之前(会早几毫秒)触发的,不过在Chrome和Firefox中,这个时候确

实已经可以完全访问并操作(appendChild、removeChild)DOM元素了(即DOM tree已经ready)。

本文转自http://hi.baidu.com/flondon/item/247985275ba2833694f62b9a

猜你喜欢

转载自xst4002.iteye.com/blog/1570880
今日推荐