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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3483919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 01:18:26  来源:igfitidea点击:

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

javascriptinternet-explorerasynchronouslazy-loading

提问by Plokko

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 个变量,但调试起来非常棘手(所有源代码都在一个单一的行和浏览器没有提供太多关于错误的信息,用正则表达式逐行划分代码是不可能的,因为 js 具有无限深度的块,而正则表达式根本不擅长于此)。

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;
the code below is a fix but works only if the script isn't async

它不会在 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>;

            };

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 毫秒检查一次的代码,它并没有那么糟糕,并且比 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)
  • Use AJAX and global eval only with IE(may be a solution,i don't use 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)
  • Test script.onreadystatechange (only on IE) every X time until it's loaded(UGLY!!!)
  • 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)
  • Add a code on the source of each script (AVOID like said on endpage)
  • fix the script.onload for IE(using addEventListener/attachEvent?!?)
  • 使用 AJAX 和全局 eval 加载脚本(调试地狱)
  • 仅在 IE 中使用 AJAX 和全局 eval(可能是一个解决方案,我不使用 IE)
  • 仅当脚本包含错误时才使用 AJAX 和全局 eval(我需要检查计时问题,因为即使调用是异步的,我也用我的代码“模拟”同步代码)
  • 每 X 次测试 script.onreadystatechange(仅在 IE 上)直到它被加载(丑陋!!!)
  • 使用 window.onload :避免,它需要对所有页面收费,我需要在仅启动一个脚本时调用它(请参阅endpage的详细信息)
  • 在每个脚本的源代码上添加代码(避免像在 endpage 上所说的那样)
  • 修复 IE 的 script.onload(使用 addEventListener/attachEvent ?!?)



PLEASE PAY ATTENTION:请注意:


我不想使用 window.onload 因为它仅在加载所有页面时才触发,我需要在仅加载目标脚本时触发它(我的延迟加载脚本要复杂得多,所以请不要不要问为什么);


i DO NOT WANT to use ANY third party library(like jquery,prototype,etc.)我不想使用任何第三方库(如 jquery、prototype 等)


我什至不想编辑目标脚本源(如使用 JSPON 或添加脚本以提醒脚本已加载时)。

Hope that's not too much! Thanks.

希望不要太多!谢谢。

回答by Plokko

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 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,我将简单地使用异步 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---

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
  • file2 with a 500 error
  • file3 with 1s of loading
  • 加载时间为 4 秒的文件 1
  • file2 出现 500 错误
  • file3 加载 1 秒

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!

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

回答by nozer0

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 asyncis set or not, using readyState = 'loaded'to check error is not enough. In fact, loadedwill be triggered in situations loading error script or the first time to load correct script.

不得不说,不管有async没有设置,仅仅readyState = 'loaded'用来检查错误是不够的。实际上,loaded在加载错误脚本或第一次加载正确脚本的情况下都会触发。

You can append srcwith random query string to disable the cache, then check the readyState.

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

回答by Yuri Izgarshev

Try this one: https://stackoverflow.com/a/18840568/2785975. Here the problem for IE7-8 with onerror event is described and decision is shown.

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

回答by prodaea

ignore the junk below. the nextSibling thing was a result of being in the debugger and wasn't really reproducible in the real world. instead, i would have to recommend checking out www.requirejs.org

忽略下面的垃圾。nextSibling 的事情是在调试器中的结果,在现实世界中并不能真正重现。相反,我不得不建议查看 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 中可以找到的包含或导入语句差不多的方法。

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;



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