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

Plo*_*kko 5 javascript internet-explorer asynchronous lazy-loading

我重建我的延迟加载模块接受asyncronus请求,但我有一个很大的问题:
IE浏览器不支持script.onload/onerror的!

旧的脚本并在全球范围EVAL与AJAX同步调用读取目标脚本源,它工作得很好,它是跨浏览器,我可以把它异步编辑1个变量,但它是非常棘手的调试(所有的源代码在一个单一的执行线和浏览器不给予有关的错误太多的相关信息,将代码通过线与正则表达式是不可能的,因为JS有无限的深度和正则表达式块根本不擅长这一点).

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

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>;
Run Code Online (Sandbox Code Playgroud)

它不适用于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>;

            };
Run Code Online (Sandbox Code Playgroud)

我可以每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);
Run Code Online (Sandbox Code Playgroud)

我试图使用addEventListener/attachEvent函数但它似乎不起作用(甚至使用Web上的addEvent函数)

总结选项似乎是:

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


请注意:
我不希望使用的window.onload,因为它只是发射时加载的所有页面,我需要启动它时,只有目标脚本被加载(我懒加载脚本是一个复杂得多,所以请不要不问为什么);
我不希望使用任何第三方库(如jQuery,样机等),
我甚至不希望编辑目标脚本源(当使用或JSPON添加脚本以提醒加载脚本等).

希望不是太多!谢谢.

Plo*_*kko 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---
Run Code Online (Sandbox Code Playgroud)

这在大多数浏览器上运行良好(IE/chrome/firfox 目前已测试)并且我测试了加载 3 个文件:

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

它们在所有浏览器中总共加载了 40XX 毫秒(浏览器需要一些额外的时间来调用 onload/onerror 脚本),我还可以(使用我的惰性加载器脚本)模拟同步加载仅在之后执行代码队列中的所有文件均已加载。

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

  • 我会适应你的解决方案,除了它有一个缺点,这对我来说是一个阻碍:你对跨域 AJAX 调用以及本地 (file://) AJAX 调用有超级安全限制,:( 因此使得系统不可靠。 (2认同)