Динамически создавая script: readyState никогда не "завершает"

Я пытаюсь сделать что-то ПОСЛЕ ПОЛЬЗОВАНИЯ script. (IE8)

Script Я использую для тестирования: 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');}
};

В моем случае "полный" никогда не отображается, "загруженный" показывает, даже если URL-адрес недействителен. Таким образом, нет способа узнать, загружен ли script с ошибкой UNDER IE.

Я что-то делаю неправильно? Почему я никогда не получаю полное состояние?

UPDATE

ОК, я просто прочитал несколько статей, и кажется, что readystate не является надежным способом обнаружения загрузки script.

Так есть ли другой способ сделать это? без jQuery, но чистый Javascript.

Ответ 1

В соответствии с вашим комментарием, здесь приведена схема динамического добавления тега script с использованием 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

Я нашел трюк, как сделать script node стать "полным" в IE7 и IE8. А также, как обнаружить, когда действительно возникает ошибка при загрузке script (node.onerror работает только в IE9 +). Хак находится в

  • НЕ вставлять вновь созданный элемент в DOM (сразу).
  • Вызов свойства node.children и проверка свойства node.onreadystate сразу после него. Если свойство изменяется на "complete" - вы загрузили script, он изменился на "загрузка" - это наверняка ошибка загрузки script.

Попробуйте!

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

Ответ 3

Обнаружение завершения загрузки

[..] Одна веб-страница предложила настроить некоторые обработчики событий, которые будут вызываться, когда загрузка будет завершена. Мы делаем это, добавляя следующие строки к предыдущему коду:

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

Здесь мы создаем два разных обработчика событий для вновь созданного тега script. В зависимости от браузера предполагается, что один или другой из этих двух обработчиков будет вызван, когда script завершит загрузку. Обработчик onreadystatechange работает только с IE. Обработчик onload работает с браузерами Gecko и Opera.

Тест "this.readyState ==" complete полностью не работает. Готовое государство теоретически проходит ряд состояний:

  • 0 неинициализирован
  • 1 загрузка
  • 2 загружен
  • 3 интерактивных
  • 4 полный

Но на самом деле состояния могут быть пропущены. По моему опыту с IE 7 вы получаете либо загруженное событие, либо завершенное событие, но не оба.

Возможно, это связано с тем, загружается ли вы из кеша или нет, но, похоже, есть другие факторы, которые влияют на то, какие события вы получаете. Иногда я получаю загрузочные или интерактивные события, а иногда и нет. Возможно, тест должен быть "this.readyState ==" загружен "|| this.readyState == 'complete'", но этот риск запускается дважды.

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

UPDATE

Пожалуйста, можете ли вы включить свой обратный вызов script.onreadystatechange с помощью этого:

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

};

Еще одна вещь, которую я заметил, это то, что вы выполняете сравнение строк с оператором ==. Это может ввести в заблуждение. Вместо этого используйте ===.