Я могу определить, когда содержимое iframe загружено, с помощью события нагрузка. К сожалению, для моих целей здесь есть две проблемы:
Есть ли способ надежно определить, произошла ли какая-либо из вышеперечисленных ошибок?
Я пишу полу-веб-приложение для полу-рабочего стола на основе Mozilla / XULRunner, поэтому приветствуются решения, которые работают только в Mozilla.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если у вас есть контроль над страницей iframe (и страницы находятся на одном доменном имени), стратегия может быть следующей:
var iFrameLoaded = false;true, вызывая из документа iframe, например, родительскую функцию (setIFrameLoaded();).iFrameLoaded с помощью объекта timer (установите таймер на предпочитаемый вами предел времени ожидания) - если флаг все еще ложен, вы можете сказать, что iframe не загружался регулярно.Надеюсь, это поможет.
Разные ресурсы будут загружаться в разные периоды времени. Эта непредсказуемость убьет ваш подход Дэниела Кэссиди, поскольку вам придется предусмотреть достаточно длительный тайм-аут. Тем временем кратковременные ошибки загрузки будут просто отображаться на экране до тех пор, пока таймер не примет решение, что ресурс не удалось загрузить, и не обработает ошибку.
Недавно у меня возникла эта проблема, и мне пришлось прибегнуть к настройке действия Javascript Polling на родительской странице (которая содержит тег IFRAME). Эта функция JavaScript проверяет содержимое IFRAME на наличие явных элементов, которые должны существовать только в ХОРОШИМ ответе. Это, конечно, предполагает, что вам не нужно иметь дело с нарушением «политики одного и того же происхождения».
Вместо проверки всех возможных ошибок, которые могут быть сгенерированы множеством различных сетевых ресурсов ... Я просто проверил один постоянный положительный элемент (ы), который, как я знаю, должен быть в хорошем ответе.
После заранее определенного времени и / или количества неудачных попыток обнаружить ожидаемый элемент (ы), JavaScript изменяет атрибут SRC IFRAME (для запроса от моего сервлета) удобную для пользователя страницу ошибки вместо отображения типичного сообщения HTTP ERROR. . JavaScript также может легко изменить атрибут SRC, чтобы сделать совершенно другой запрос.
function checkForContents(){
var contents=document.getElementById('myiframe').contentWindow.document
if (contents){
alert('found contents of myiframe:' + contents);
if (contents.documentElement){
if (contents.documentElement.innerHTML){
alert("Found contents: " +contents.documentElement.innerHTML);
if (contents.documentElement.innerHTML.indexOf("FIND_ME") > -1){
openMediumWindow("woot.html", "mypopup");
}
}
}
}
}
Я думаю, что событие pageshow запускается для страниц с ошибками. Или, если вы делаете это из Chrome, тогда вы проверяете запрос слушателя прогресса, чтобы узнать, является ли он каналом HTTP, и в этом случае вы можете получить код состояния.
Что касается зависимостей страниц, я думаю, вы можете сделать это только из chrome, добавив прослушиватель событий onerror, и даже тогда он будет находить ошибки только в элементах, а не в фонах CSS или других изображениях.
Имейте идентификатор для самого верхнего (основного) элемента на странице, которая загружается в ваш iframe.
в обработчике загрузки вашего iframe проверьте, возвращает ли getElementById () ненулевое значение. Если это так, iframe загружен успешно. иначе это не удалось.
в этом случае поместите frame.src = "about: blank". Перед этим обязательно снимите грузоподъемное устройство.
что, если у нас нет контроля над страницей, которую мы загружаем. тогда как справиться с этой ситуацией ??
Точно не отвечает на ваш вопрос, но мой поиск ответа привел меня сюда, поэтому я отправляю сообщение на тот случай, если у кого-то еще есть аналогичный мне запрос.
Он не совсем использует событие загрузки, но он может определить, доступен ли веб-сайт и может ли он быть вызван (если это так, то iFrame, теоретически, должен загружаться).
Сначала я подумал сделать вызов AJAX, как и все остальные, за исключением того, что у меня изначально это не сработало, так как я использовал jQuery. Он отлично работает, если вы выполняете XMLHttpRequest:
var url = http://url_to_test.com/
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status != 200) {
console.info("iframe failed to load");
}
};
xhttp.open("GET", url, true);
xhttp.send();
Редактировать:
Таким образом, этот метод работает нормально, за исключением того, что он имеет много ложных отрицаний (собирает много вещей, которые будут отображаться в iframe) из-за маларкости перекрестного происхождения. Способ, которым я обошел это, заключался в том, чтобы выполнить CURL / веб-запрос на сервере, а затем проверить заголовки ответа на: а) если веб-сайт существует, и б) если в заголовках установлен x-frame-options.
Это не проблема, если у вас есть собственный веб-сервер, так как вы можете сделать для него свой собственный вызов API.
Моя реализация в node.js:
app.get('/iframetest',function(req,res){ //Call using /iframetest?url=url - needs to be stripped of http:// or https://
var url = req.query.url;
var request = require('https').request({host: url}, function(response){ //This does an https request - require('http') if you want to do a http request
var headers = response.headers;
if (typeof headers["x-frame-options"] != 'undefined') {
res.send(false); //Headers don't allow iframe
} else {
res.send(true); //Headers don't disallow iframe
}
});
request.on('error',function(e){
res.send(false); //website unavailable
});
request.end();
});
Это очень поздний ответ, но я оставлю его тем, кому он нужен.
Задача:загружать содержимое iframe из разных источников, выдавать onLoaded в случае успеха и onError при ошибке загрузки.
Это наиболее кроссбраузерное решение, независимое от происхождения, которое я мог разработать. Но сначала я кратко расскажу о других подходах, которые у меня были, и о том, почему они плохие.
1. iframe Меня немного шокировало, что iframe имеет только событие onload и вызывается при загрузке и при ошибке, нет возможности узнать, ошибка это или нет.
2. performance.getEntriesByType ('ресурс'). Этот метод возвращает загруженные ресурсы. Похоже на то, что нам нужно. Но какой позор, firefox всегда добавляет ресурс в массив ресурсов, независимо от того, загружен он или вышел из строя. По экземпляру Resource невозможно узнать, был ли он успешным. По-прежнему. Кстати, в ios <11 этот способ не работает.
3. сценарий Я пытался загрузить html с помощью тега <script>. Выдает onload и onerror правильно, к сожалению, только в Chrome.
И когда я был готов сдаться, мой старший коллега рассказал мне о html4-теге <object>. Он похож на тег <iframe>, за исключением того, что у него есть резервные варианты, когда контент не загружен. Это похоже на то, что нам нужно! К сожалению, это не так просто, как кажется.
РАЗДЕЛ КОДА
var obj = document.createElement('object');
// we need to specify a callback (i will mention why later)
obj.innerHTML = '<div style = "height:5px"><div/>'; // fallback
obj.style.display = 'block'; // so height=5px will work
obj.style.visibility = 'hidden'; // to hide before loaded
obj.data = src;
После этого мы можем установить некоторые атрибуты для <object>, как мы хотели сделать с iframe. Единственное отличие, мы должны использовать <params>, а не атрибуты, а их имена и значения идентичны.
for (var prop in params) {
if (params.hasOwnProperty(prop)) {
var param = document.createElement('param');
param.name = prop;
param.value = params[prop];
obj.appendChild(param);
}
}
А теперь самое сложное. Как и многие подобные элементы, <object> не имеет спецификаций для обратных вызовов, поэтому каждый браузер ведет себя по-разному.
load.load и error.Похоже, ничем не отличается от iframe, getEntriesByType, script ....
Но у нас есть запасной вариант для браузера! Итак, поскольку мы устанавливаем резервный вариант (innerHtml) напрямую, мы можем определить, загружен ли <object> или нет.
function isReallyLoaded(obj) {
return obj.offsetHeight !== 5; // fallback height
}
/**
* Chrome calls always, Firefox on load
*/
obj.onload = function() {
isReallyLoaded(obj) ? onLoaded() : onError();
};
/**
* Firefox on error
*/
obj.onerror = function() {
onError();
};
Но что делать с Safari? Старый добрый setTimeout.
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
onLoaded();
} else {
onError();
}
}
setTimeout(interval, 100);
};
function hasResult(obj) {
return obj.offsetHeight > 0;
}
Ага .... не так быстро. Дело в том, что <object> в случае сбоя не упоминается в спецификациях:
Итак, код нуждается в небольшом улучшении
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
interval.count++;
// needs less then 400ms to fallback
interval.count > 4 && onLoadedResult(obj, onLoaded);
} else {
onErrorResult(obj, onError);
}
}
setTimeout(interval, 100);
};
interval.count = 0;
setTimeout(interval, 100);
Ну а для начала загрузки
document.body.appendChild(obj);
Это все. Я попытался объяснить код во всех деталях, так что это может показаться не таким уж глупым.
P.S. WebDev отстой
1) Зачем добавлять JavaScript на страницу iframe? С таким же успехом я мог бы использовать setTimeout вместе с событием загрузки. 2) Это не позволяет надежно определить, произошел ли сбой загрузки или почему, просто удастся ли она выполнить в течение установленного времени. 3) Не определяет случай, когда зависимости страниц не загружаются.