简体   繁体   English

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

[英]script onload/onerror with IE(for lazy loading) problems

I'm rebuilding my lazy loader module to accept asyncronus request but i have a BIG problem: 我正在重建我的惰性加载程序模块以接受异步请求,但是我遇到了一个大问题:
internet explorer don't support script.onload/onerror!!! Internet Explorer不支持script.onload / onerror !!!

The old script did globally eval the target script source read with an ajax sync call, it works very well,it's cross browser and i can make it async editing 1 variable but it's very tricky to debug(ALL the source code is executed in one single line and the browser gives not to much infos about the errors,dividing the code by line with a regexp is IMPOSSIBLE because js have blocks with infinite depth and regexp are simply not good at this). 旧脚本在全局范围内评估了通过ajax同步调用读取的目标脚本源,它工作得很好,它是跨浏览器,我可以使其异步编辑1个变量,但是调试起来非常棘手(所有源代码都在一个代码中执行行和浏览器没有提供太多有关错误的信息,使用regexp逐行划分代码是不可能的,因为js具有无限深度的块,而regexp根本不擅长此操作)。

This is the code that i use to create the script(a classic): 这是我用来创建脚本的代码(经典):

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>;

it won't work on IE because it doesen't support onload and onerror with the script; 它不适用于IE,因为它不支持脚本的onload和onerror。
the code below is a fix but works only if the script isn't async 下面的代码是一个修复程序,但仅在脚本不异步时有效

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>;

            };

i can test it every X milliseconds until the script is loaded but it's an ugly solution and i want to avoid it. 我可以每X毫秒测试一次,直到脚本加载完毕,但这是一个丑陋的解决方案,我想避免使用它。

EDIT: this is the code i tryed to check every X ms if the script is loaded, it's not that bad and it works better than ajax;the problem is that i can't know if the script is loaded with success or with error(onload or onerror). 编辑:这是我试图在脚本加载后每隔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);

i tryed to use addEventListener/attachEvent functions but it didn't seem to work(even using addEvent functions from the web) 我尝试使用addEventListener / attachEvent函数,但似乎没有用(即使使用网络上的addEvent函数)

summarizing the options seems to be: 总结选项似乎是:

  • Use AJAX and global eval to load the script(debugging hell) 使用AJAX和全局eval加载脚本(调试地狱)
  • Use AJAX and global eval only with IE(may be a solution,i don't use IE) 仅对IE使用AJAX和全局评估(可能是一种解决方案,我不使用IE)
  • Use AJAX and global eval only if the script contains errors(i need to check timings problems because with my code i "simulate" syncronous code even if the call is async) 仅当脚本包含错误时才使用AJAX和全局评估(我需要检查计时问题,因为即使调用是异步的,我的代码也“模拟”了同步代码,因此我需要检查计时问题)
  • Test script.onreadystatechange (only on IE) every X time until it's loaded(UGLY!!!) 每X次测试script.onreadystatechange(仅在IE上),直到加载完毕(丑陋!!!)
  • Use window.onload : AVOID,it need to charge ALL the page,i need to call it when ONLY one script is launched(see details on endpage) 使用window.onload:避免,它需要对所有页面收费,我仅在启动一个脚本时才需要调用它(请参见末页上的详细信息)
  • Add a code on the source of each script (AVOID like said on endpage) 在每个脚本的源代码上添加一个代码(避免在首页上显示该代码)
  • fix the script.onload for IE(using addEventListener/attachEvent?!?) 修复IE的script.onload(使用addEventListener / attachEvent?!?)


PLEASE PAY ATTENTION: 请注意:
i don't want to use window.onload because it's fired only when ALL the page is loaded,i need to fire it when only the target script is loaded(my lazy loading script is a lot more complex so please don't ask why); 我不想使用window.onload,因为仅在加载所有页面时才触发它,我只在目标脚本被加载时才触发它(我的惰性加载脚本要复杂得多,所以请不要问为什么);
i DO NOT WANT to use ANY third party library(like jquery,prototype,etc.) , 我不想使用任何第三方库(例如jquery,prototype等)
i don't even want to edit the target script source(like when using JSPON or adding a script to alert that the script is loaded). 我什至不想编辑目标脚本源(例如当使用JSPON或添加脚本以警告脚本已加载时)。

Hope that's not too much! 希望不要太多! Thanks. 谢谢。

This is one solution: if it's IE i'll simply load the text with an async ajax call and then set the script.text to the loaded data. 这是一种解决方案:如果是IE,我将使用异步ajax调用简单地加载文本,然后将script.text设置为已加载的数据。 IE seems to lock onload and onerror(for security reasons?)and not script.text(some other browsers may not allow it for security resons to prevent XSS attacks like on iframes),i don't know why microsoft can't simply respect standards,i simply hate ie and "tricks" to fix theyr's desing problems. 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---

this works well on most browsers(IE/chrome/firfox tested for now)and i tested loading 3 files: 这在大多数浏览器上都运行良好(目前已测试IE / chrome / firfox),我测试了加载3个文件:

  • file1 with load time of 4s 加载时间为4s的file1
  • file2 with a 500 error file2出现500错误
  • file3 with 1s of loading 加载1s的file3

and they're loaded in a total of 40XX ms in all browsers(some extra time is taken by the browser to call the onload/onerror script),i can also(with my lazy loader script)simulate a sync loading executing code only after all files in queue are loaded. 并且它们在所有浏览器中总共加载了40XX毫秒(浏览器花费了一些额外的时间来调用onload / onerror脚本),我也可以(使用我的惰性加载器脚本)模拟仅在队列中的所有文件都已加载。

If you know a better way or if you know errors that may occur in this implementation please reply! 如果您知道更好的方法,或者您知道此实现中可能发生的错误,请回复! Thanks! 谢谢!

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

};

I have to say that regardless whether async is set or not, using readyState = 'loaded' to check error is not enough. 我必须说,无论是否设置了async ,使用readyState = 'loaded'来检查错误是不够的。 In fact, loaded will be triggered in situations loading error script or the first time to load correct script. 事实上, loaded会在加载错误的脚本或第一次加载正确的脚本的情况下被触发。

You can append src with random query string to disable the cache, then check the readyState . 您可以在src后面附加随机查询字符串以禁用缓存,然后检查readyState

Try this one: https://stackoverflow.com/a/18840568/2785975 . 试试这个: https : //stackoverflow.com/a/18840568/2785975 Here the problem for IE7-8 with onerror event is described and decision is shown. 此处描述了带有onerror事件的IE7-8的问题并显示了决策。

ignore the junk below. 忽略下面的垃圾。 the nextSibling thing was a result of being in the debugger and wasn't really reproducible in the real world. nextSibling的原因是在调试器中的结果,并且在现实世界中并不是真正可复制的。 instead, i would have to recommend checking out www.requirejs.org 相反,我将不得不建议查看www.requirejs.org

it provides a method that is about as close to an include or import statement as you could find in js. 它提供的方法与js中包含的include或import语句差不多。

this is a totally goofball solution, and i will be following this thread for comments about why this works, but here goes how i fixed this without a timer. 这是一个完全愚蠢的解决方案,我将关注这个主题,以评论其工作原理,但是这里介绍了如何在没有计时器的情况下解决此问题。

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;

like i said i don't know WHY nextSibling is null on a 404'd attempt, but if the js url was correct, nextSibling had a value. 就像我说的,我不知道为什么在404尝试时nextSibling为null,但是如果js网址正确,则nextSibling具有值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM