javascript 动态创建脚本:readyState 永远不会“完成”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6946631/
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 22:26:26  来源:igfitidea点击:

dynamically creating script: readyState never "complete"

javascriptreadystateonreadystatechange

提问by pepsi600

I'm trying to do something AFTER a script is completely loaded. (IE8)

我正在尝试在脚本完全加载后做一些事情。(IE8)

Script I use for testing: http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
and the invalid one: http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.minaaaaaaaa.js

我用于测试的脚本:http: //ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
和无效的:http: //ajax.googleapis.com/ajax/libs/ jquery/1.5.1/jquery.minaaaaaaaa.js

The code...

代码...

var script = create the element and append to head...

// this works fine with FF/Chrome/...
script.onload = function() {alert('script loading complete');}
script.onerror = function() {alert('error loading script');}

// and for IE
script.onreadystatechange = function() {
    // this will alert 1.loading 2.loaded
    alert(this.readyState);

    // this never works
    if(this.readyState == 'complete') {alert('script loading complete');}

    // this works with either a valid or INVALID url
    else if(this.readyState == 'loaded') {alert('script loaded');}
};

In my case, the "complete" never shows, the "loaded" shows even if a url is invalid. So there's no way to tell if a script is CORRECTLY loaded UNDER IE.

就我而言,“完整”永远不会显示,即使网址无效,“加载”也会显示。所以没有办法判断脚本是否在 IE 下正确加载。

Am I doing something wrong? How come I never get the complete state?

难道我做错了什么?为什么我从来没有得到完整的状态?

UPDATE

更新

OK, I just read some articles and it seems that readystate is not a reliable way to detect script loading.

好吧,我刚刚读了一些文章,似乎readystate 不是检测脚本加载的可靠方法。

So is there another way to do so? without jQuery, but pure Javascript.

那么还有另一种方法吗?没有 jQuery,而是纯 Javascript。

采纳答案by FK82

As per your comment, here's a schematic of how to dynamically add a script tag using XHR (XMLHttpRequest):

根据您的评论,这是如何使用 XHR ( XMLHttpRequest)动态添加脚本标记的示意图:

var handleRequest = function( ) { //!! set up the handleRequest callback

     if(this.status != undefined) {

         /* do something with the status code here */

     }

     if(this.readyState == 4) {

          var script = document.createElement("script") ;
              script.setAttribute("type","text/javascript") ;
          var text = document.createTextNode(this.responseText) ;
              script.appendChild(text) ;

          var head = document.getElementsByTagName("head")[0] ;
              head.insertBefore(script,head.firstChild) ;

     }

} ;

var request ; //!! supposing you have a way to get a working XHR Object

//.. set the XHR Object

request.open("GET",url,true) ;
request.overrideMimeType("text/javascript") ;
request.onreadystatechange = handleRequest ;
request.send(null) ;

Please keep in mind that this is only to give you an idea of what I mean. A working example would have to be way more elaborate judging from the jQuery source code.

请记住,这只是为了让您了解我的意思。从 jQuery 源代码来看,一个工作示例必须更加精细。



Links:

链接:

回答by Yuri Izgarshev

I've found out a trick how to make script node become 'complete' in IE7 and IE8. And also how to detect when error really happens when loading script (node.onerror working only in IE9+). The hack is in

我发现了一个技巧,如何使脚本节点在 IE7 和 IE8 中变得“完整”。以及如何检测加载脚本时真正发生错误的时间(node.onerror 仅在 IE9+ 中工作)。黑客在

  1. NOT inserting the newly created element into DOM (at once).
  2. Calling node.children property and checking node.onreadystate property right after it. If the property changes to 'complete' - you have loaded script, it it changes to 'loading' - it's for sure script loading error.
  1. 不要将新创建的元素插入 DOM(一次)。
  2. 调用 node.children 属性并在它之后检查 node.onreadystate 属性。如果属性更改为“完成”-您已加载脚本,则它会更改为“正在加载”-肯定是脚本加载错误。

Try it!

试试看!

var node = document.createElement('script');
node.src = 'some-[un]existing-url.js';
node.type = 'text/javscript';

node.onreadystatechange = (function(node) { 
    return function () {
        if (/loaded|complete/.test(node.readyState)) {
            _finish();
        }
    };
})(node);

var _finish=function() {

        if (node.readyState == 'complete') {
            // insert node only after completing the request, though this is not necessary
            var head = document.head;
            head || (head = document.getElementsByTagName('head')[0]);
            head.appendChild(node);
            // call success function
            _success();
            return;
        }

        var firstState = node.readyState;

        // hack: calling 'children' property changes node's readyState from 'loaded' to complete
        // (if script was loaded normally) or to 'loading' - if error detected
        node.children;

        // error detected
        if (firstState == 'loaded' && node.readyState == 'loading') {
            // custom error code
            _error();
        }
}

回答by user278064

Detecting Load Completion

检测负载完成

[..] One web page suggested setting up some event handlers that will be called when the load is complete. We do that by adding the following lines to the previous code:

[..] 一个网页建议设置一些在加载完成时将被调用的事件处理程序。我们通过在前面的代码中添加以下几行来做到这一点:

var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.onreadystatechange= function () {
  if (this.readyState == 'complete') helper();
}
script.onload= helper;
script.src= 'helper.js';
head.appendChild(script);

Here we set up two different event handlers on the newly created script tag. Depending on the browser, one or the other of these two handlers is supposed to be called when the script has finished loading. The onreadystatechange handler works on IE only. The onload handler works on Gecko browsers and Opera.

这里我们在新创建的脚本标签上设置了两个不同的事件处理程序。根据浏览器的不同,应该在脚本加载完成后调用这两个处理程序中的一个。onreadystatechange 处理程序仅适用于 IE。onload 处理程序适用于 Gecko 浏览器和 Opera。

The "this.readyState == 'complete'" test doesn't actually entirely work. The readyState theoretically goes through a series of states:

“this.readyState == 'complete'”测试实际上并不完全有效。readyState 理论上会经历一系列的状态:

  • 0 uninitialized
  • 1 loading
  • 2 loaded
  • 3 interactive
  • 4 complete
  • 0 未初始化
  • 1 加载
  • 2 加载
  • 3互动
  • 4 完成

But in fact, states may be skipped. In my experience with IE 7, you get either a loaded event or a completed event, but not both.

但实际上,可以跳过状态。根据我使用 IE 7 的经验,您会获得加载事件或完成事件,但不能同时获得两者。

It may have something to do with whether you are loading from cache or not but there seem to be other factors that influence which events you get. Sometimes I get loading or interactive events too, and sometimes I don't. It's possible the test should be "this.readyState == 'loaded' || this.readyState == 'complete'", but that risks triggering twice.

这可能与您是否从缓存加载有关,但似乎还有其他因素会影响您获得的事件。有时我也会收到加载或交互事件,有时我不会。测试可能应该是“this.readyState == 'loaded' || this.readyState == 'complete'”,但这有触发两次的风险。

http://unixpapa.com/js/dyna.html

http://unixpapa.com/js/dyna.html

UPDATE

更新

Please, can you sobstitute your script.onreadystatechangecallback with this:

拜托,你能不能script.onreadystatechange用这个来代替你的回调:

newjs.onreadystatechange = function () {
   if (newjs.readyState === 'loaded' || newjs.readyState === 'complete') {
      newjs.onreadystatechange = null;
      alert('script is complete or loaded.");
   }

};

};

An other thing i've noticed is that you're doing string comparison with ==operator. This can be misleading. Use ===instead.

我注意到的另一件事是您正在与==运算符进行字符串比较。这可能会产生误导。使用===来代替。