脚本onload / onerror与IE(用于延迟加载)问题

时间:2010-08-14 15:08:22

标签: javascript internet-explorer asynchronous lazy-loading

我正在重建我的懒惰加载器模块以接受asyncronus请求,但我有一个大问题:
internet explorer不支持script.onload / onerror !!!

旧脚本通过ajax同步调用全局评估目标脚本源读取, 它工作得很好,它是跨浏览器,我可以使它异步编辑1变量,但它是非常棘手的调试(所有的源代码在一行中执行,浏览器提供了很多关于错误的信息,划分代码带有正则表达式的行是不可能的,因为js具有无限深度的块,而regexp根本就不擅长这个。)

这是我用来创建脚本的代码(经典):

var script = document.createElement('script');
script.type = 'text/javascript';
script.src =name;
script.name =name;
script.async = true;
script.onload=<my_onload_code>;
script.onerror=<my_onerror_code>;

它不适用于IE,因为它不支持onload和onerror与脚本;
下面的代码是一个修复程序,但仅在脚本不是异步

时才有效
if(script.onreadystatechange!==undefined)//only IE T_T
            script.onreadystatechange = function() {
                    if (script.readyState == 'loaded')//ERROR LOADING
                        <my_onerror_code>;
                    else
                    if(script.readyState == 'complete')//loaded
                        <my_onload_code>;

            };

我可以每隔X毫秒测试一次,直到加载脚本,但这是一个丑陋的解决方案,我想避免它。

编辑:这是我尝试检查每个X ms的代码,如果脚本已加载,它没有那么糟糕,它比ajax更好;问题是我不知道是否脚本加载成功或错误(onload或onerror)。

var script = document.createElement('script');
script.type = 'text/javascript';
script.src =name;
script.name =name;
script.async = true;

    script.onload=function(){Lazy_loader.onload(this);};
    script.onerror=function(){Lazy_loader.onerror(this);};

    if(script.onreadystatechange!==undefined){//ie fix T_T 
        script.timer=setInterval(function(){
                    if (script.readyState == 'loaded' || script.readyState == 'complete')}//ERROR LOADING

                        if(LOADED???)//loaded
                            Lazy_loader.onload(script);
                        else
                            Lazy_loader.onerror(script);

                        clearInterval(script.timer);
                    }

                    },100);

    }

document.getElementsByTagName('head')[0].appendChild(script);

我尝试使用addEventListener / attachEvent函数但它似乎不起作用(甚至使用来自web的addEvent函数)

总结选项似乎是:

  • 使用AJAX和global eval加载脚本(调试地狱)
  • 仅在IE上使用AJAX和全局评估(可能是解决方案,我不使用IE)
  • 仅当脚本包含错误时才使用AJAX和全局eval(我需要检查时间问题,因为我的代码即使呼叫是异步的,也会“模拟”同步代码)
  • 每隔X次测试script.onreadystatechange(仅在IE上),直到它被加载(UGLY !!!)
  • 使用window.onload:AVOID,它需要为所有页面充电,我只需要在启动一个脚本时调用它(详情请见endpage)
  • 在每个脚本的源代码上添加代码(AVOID,如在endpage上所述)
  • 修复IE的script.onload(使用addEventListener / attachEvent?!?)


请注意:
我不想使用window.onload,因为只有当所有页面都被加载时它才被触发,我需要在只加载目标脚本时触发它(我的延迟加载脚本要复杂得多,所以请不要问为什么);
我不想使用任何第三方库(如jquery,原型等)

我甚至不想编辑目标脚本源(比如使用JSPON或添加脚本来警告脚本已加载)。

希望不是太多! 感谢。

4 个答案:

答案 0 :(得分:4)

这是一个解决方案: 如果是IE,我只需使用异步ajax调用加载文本,然后将script.text设置为加载的数据。 IE似乎锁定onload和onerror(出于安全原因?)而不是script.text(其他一些浏览器可能不允许它用于安全措施以防止像iframe这样的XSS攻击),我不知道为什么微软不能简单地尊重标准,我只是讨厌ie和“技巧”来解决他们的设计问题。

    var script = document.createElement('script');
    script.type = 'text/javascript';      
    //---start IE fix--- 
    if(window.ActiveXObject){//ie fix T_T 
            var xmlhttp=null;
            try {
                xmlhttp = new XMLHttpRequest();
            }catch(e){
                try{
                    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
                }catch(e){
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
            }  
            xmlhttp.onreadystatechange  = function() {
            try{
                if(this.done!==undefined)
                    return;

                if(this.status >= 200 && this.status < 300){//loaded
                    this.done=true;
                    script.text=this.responseText;
                    document.getElementsByTagName('head')[0].appendChild(script);
                    Lazy_loader.onload({name:name});
                }
                if(this.status >= 400){
                    this.done=true;
                    Lazy_loader.onerror({name:name});
                    }
                }catch(e){}
            };
            xmlhttp.open('get',name,true);                             
            xmlhttp.send(null); 

        }
        else{//browser that support script.onload/onerror
            script.src =name;
            script.name =name;
            script.async = true;  
            script.onload=function(){Lazy_loader.onload(this);};
            script.onerror=function(){Lazy_loader.onerror(this);};
            document.getElementsByTagName('head')[0].appendChild(script); 
        }
        //---end IE fix---

这适用于大多数浏览器(IE / chrome / firfox现在测试),我测试加载3个文件:

  • file1,加载时间为4秒
  • file2,出现500错误
  • file3,加载时间为

并且它们在所有浏览器中加载总共40XX ms(浏览器需要一些额外的时间来调用onload / onerror脚本),我也可以(使用我的延迟加载器脚本)模拟同步加载执行只有在加载队列中的所有文件后才能编码。

如果您知道更好的方法,或者您知道此实施中可能出现的错误,请回复! 谢谢!

答案 1 :(得分:1)

script.onreadystatechange = function() {
    if (script.readyState == 'loaded')//ERROR LOADING
        <my_onerror_code>;
    else if(script.readyState == 'complete')//loaded
        <my_onload_code>;

};

我必须说,无论是否设置async,使用readyState = 'loaded'检查错误是不够的。实际上,loaded将在加载错误脚本或第一次加载正确脚本的情况下触发。

您可以使用随机查询字符串附加src来禁用缓存,然后检查readyState

答案 2 :(得分:0)

忽略下面的垃圾。下一个兄弟的事情是在调试器中的结果,并且在现实世界中不能真正重现。相反,我不得不建议查看www.requirejs.org

它提供的方法与js中的include或import语句非常接近。

这是一个完全goofball的解决方案,我将关注这个主题,以了解为什么这样做有用,但这里是我如何修复这个没有计时器。

var url = load_obj.url;
var callback  = load_obj.callback;
var head = document.getElementsByTagName('head')[0];
var appendage;
var complete = false;
appendage = document.createElement('script'); appendage.type = 'text/javascript'; appendage.onload = appendage.onreadystatechange = function() { if (!complete && (!this.readyState || this.readyState === 'complete' || (this.readyState === 'loaded' && this.nextSibling != null))) { console.log('loaded via all'); complete = true; if (callback) callback(); //remove listeners appendage.onload = appendage.onreadystatechange = null; } else if (this.readyState === 'loaded' && this.nextSibling == null) { console.log('error via ie'); } appendage.onerror = function() { console.log('error via everything else'); } appendage.src = url;

就像我说我不知道​​为什么nextSibling在404'd尝试时为空,但如果js url是正确的,则nextSibling有一个值。

答案 3 :(得分:0)

试试这个:https://stackoverflow.com/a/18840568/2785975。这里描述了带有onerror事件的IE7-8的问题,并显示了决定。