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

时间:2011-08-04 18:27:40

标签: javascript readystate onreadystatechange

我正在尝试在脚本完全加载后执行某些操作。 (IE8)

我用于测试的脚本: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

代码......

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');}
};

在我的情况下,“完整”从不显示,“加载”显示即使网址无效。所以没有办法判断脚本是否在IE下正确加载。

我做错了吗?为什么我永远不会得到完整的状态?

更新

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

还有另一种方法吗?没有jQuery,但是纯粹的Javascript。

3 个答案:

答案 0 :(得分:11)

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

  1. 不要将新创建的元素插入DOM(一次性)。
  2. 调用node.children属性并在其后检查node.onreadystate属性。如果属性更改为“完成” - 您已加载脚本,则会更改为“正在加载” - 这肯定是脚本加载错误。
  3. 试试吧!

    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();
            }
    }
    

答案 1 :(得分:5)

根据您的评论,以下是如何使用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) ;

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


链接:

答案 2 :(得分:-1)

检测负载完成

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

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

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

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

  • 0未初始化
  • 1 loading
  • 2 loading
  • 3互动
  • 4完成
  

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

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

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

<强>更新

请你能用这个来阻止你的script.onreadystatechange回调:

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

};

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