Динамически создавая 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.");
}
};
Еще одна вещь, которую я заметил, это то, что вы выполняете сравнение строк с оператором ==
.
Это может ввести в заблуждение. Вместо этого используйте ===
.