解决超时调用无限调用的问题

之前我们并没有给超时调用加上时间设置,所以默认是一毫秒一次无限循环的,这样不好,写法上也是不那么合理,所以这里要加上毫秒数,并且还要运行后删除这个超时调用。

超时调用本来是不需要赋予变量名的,但是如果你要删除的话,就需要设置一个变量名,之前我们给超时调用设置了timer的变量名,这里就不多赘述了。

function addDomLoaded(fn) {
    if(document.addEventListener) {
        addEvent(document,'DOMContentLoaded',function(){
        fn();
        removeEvent(document,'DOMContentLoaded',arguments.callee);
      })
    }else {
        var timer = null;
        timer = setInterval(function() {
          try {
            document.documentElement.doScroll('left');
            fn();
            //运行完毕后删除这个超时调用
            if(timer) clearInterval(timer);
          }catch(e) {
            //跳过
          };    
        },1);
    }
}

当fn()函数运行完毕后判断这个超时调用是否存在,如果存在,就使用clearInterval()删除即可。

解决fn()多次运行

一般来说删除超时调用就可以了,但是以防万一,我们还要做个判断函数是否运行过的判断。

直接在addDomLoaded函数里面创建一个变量,初始值为false,当fn()运行一次后,让这个变量等于true,然后判断这个变量就可以了。

function addDomLoaded(fn) {
    var fox = false;
    if(document.addEventListener) {
        addEvent(document,'DOMContentLoaded',function(){
        fn();
        removeEvent(document,'DOMContentLoaded',arguments.callee);
      })
    }else {
        var timer = null;
        timer = setInterval(function() {
          try {
            document.documentElement.doScroll('left');
            doReady(fn);
            if(timer) clearInterval(timer);
          }catch(e) {
            //跳过
          };    
        },1);
    }
}

function doReady(fn) {
    if(fox) return;
    fn();
    fox = true;
}

创建一个新的函数,将fn传入,然后if判断fox,如果为true表示已经运行了一次了,于是return,下面的函数不执行。

兼容opera8,webkit引擎低于525,firefox2这些低版本浏览器

这些版本的浏览器会有问题,支持不好,我们可以适用window.onload来兼容,也可以使用document.readyState方法查询文档载入状态,或者使用另一种多次查询的方法。

document.readyState方法

我们判断返回的是loaded(已载入)或者complete(加载完毕)就可以运行fn()了。

setInterval(function(){
    if(/loaded|complete/.test(document.readyState)) {
        doReady(fn);
    }
},1);

function doReady(fn) {
    if(timer) clearInterval(timer);
    if(fox) return;
    fn();
    fox = true;
}

一样是使用超时调用无限循环,当运行完毕后我们要删除这个超时调用,所以这里也要使用删除,所以都打包到doReady函数中去。

使用多次查询的方法

上面的方法虽然可以,但是有时候不是很灵,有时候图片加载完毕了才会运行,所以这里使用新的方法

setInterval(function(){
    if(document && document.getElementById && document.getElementsByTagName && document.body) {
        doReady(fn);
    }
},1);

通过判断这四个方法是否都能执行,如果都能执行,基本上这个文档就已经解析完毕了,那么就可以运行了,然后因为也是超时调用,也要用doReady删除超时调用。

兼容写法:

//Dom解析后调用
function addDomLoaded(fn) {
    var fox = false;
    var timer = null;
    //Dom解析后调用的判断函数
    function doReady(fn) {
        if (timer) clearInterval(timer);
        if (fox) return;
        fn();
        fox = true;
    }
    if (document.addEventListener) {
        addEvent(document, 'DOMContentLoaded', function() {
            fn();
            removeEvent(document, 'DOMContentLoaded', arguments.callee);
        })
    } else if (system.ie && system.ie < 9) {
        timer = setInterval(function() {
            try {
                document.documentElement.doScroll('left');
                doReady(fn);
            } catch (e) {
                //跳过
            };
        }, 1);
    } else if ((system.opera && system.opera < 9) || (system.firefox && system.firefox < 3) || (system.webkit && system.webkit < 525)) {
        timer = setInterval(function() {
            if (document && document.getElementById && document.getElementsByTagName && document.body) {
                doReady(fn);
            }
        }, 1);
    }
}

//Dom解析后调用的调用函数
addDomLoaded(function() {
    var box = document.getElementById('box');
    alert(box.innerHTML);
});
分类: JavaScript 标签: readyStateJS DOM加载clearInterval

评论

暂无评论数据

暂无评论数据

目录