正在加载中

最后更新于 2018年12月10日

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

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

超时调用本来是不需要赋予变量名的,但是如果你要删除的话,就需要设置一个变量名,之前我们给超时调用设置了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);
});
  • weixiao kaixin tushetou jingkong deyi fanu liezui liuhan daku ganga bishi nanguo lihai qian yiwen numu tu yi haixiu se fadai minyan hehe henkaixin huaji biyiyan kuanghan maimeng shui xiaku penqi zhangzui pen aini ye niu laji ok chigua renshi kongbu shuai xiaoxiese touxiao huaixiao jingnu chihuai kaisang xiaoku koubi zhuangbi lianhong kanbujian shafa zhijing xiangjiao dabian yaowan redjing lazhu rizhi duocang chixigua hejiu xixi xiaopen goukun xiaobuchu shenme wusuowei guancha lajing chouyan xiaochi bie zhadanzui zhadanxiao