Почему событие Chrome onerror для элемента img запускается только один раз?

Почему Chrome вызывает событие onerror для элемента img только один раз, когда все остальные браузеры (IE7,8,9, FF, Opera и Safari) вызывают его неоднократно?

Есть ли способ заставить его снова повторить вызов onerror (в Chrome)?

jsfiddle

HTML:

<div id="thisWorks">
    this works in Chrome. onerror event is called once.
    <img src="http://www.asdfjklasdfasdf.com/bogus1.png" 
        onerror="fixit(this);" 
        rsrc="http://eatfrenzy.com/images/success-tick.png" />
</div>

<div id="thisDoesNotWork">
    this does not work in Chrome. onerror event is not called twice.
    <img src="http://www.asdfjklasdfasdf.com/bogus1.png" 
        onerror="fixit(this);"
        rsrc="http://www.asdfjklasdfasdf.com/bogus2.png|http://eatfrenzy.com/images/success-tick.png" />
</div>

JAVASCRIPT:

function fixit(img)
{
    var arrPhotos = img.getAttribute('rsrc').split('|');

    // change the img src to the next available
    img.setAttribute('src', arrPhotos.shift());

    // now put back the image list (with one less) into the rsrc attr
    img.setAttribute('rsrc', arrPhotos.join('|'));

    return true;    
}

EDIT: Согласно комментарию @Sunil D. о том, что Chrome не выполняет новый поиск из-за недопустимого доменного имени www.asdfjklasdfasdf.com в начальная скрипка, я пошел дальше и изменил доменное имя, чтобы оно соответствовало успешному изображению, но с другим именем файла, так что это все еще 404. Это докажет, что это не недопустимое доменное имя, вызывающее Chrome выручит со второй попытки.

РЕДАКТИРОВАТЬ: Обновлена ​​скрипка и удалено использование jquery, чтобы просто и исключить это.


person johntrepreneur    schedule 14.07.2013    source источник


Ответы (5)


Я пробовал способы, указанные выше, setAttribute('src', null) имеет побочный эффект, т.е. добавляет еще один запрос.

Наконец, я использую

    setTimeout(function(){ imgElement.src = 'http://xxxx'; }, 0)

, и это работает!

См., например, jsfiddle.

person Jess    schedule 15.07.2013
comment
просто заставьте jsFiddle запускаться в noWrap вместо выгрузки - person AlignedDev; 11.11.2014

Хорошо, понял. Внутри функции, которую вы назначаете событию onerror, установите для атрибута src значение null, прежде чем изменить его на новое значение.

img.setAttribute('src', null);

рабочая скрипта

Это каким-то образом заставляет Chrome сбросить его и заставит его повторно вызывать onerror, если последующие значения для src возвращают ошибку.

Примечание. пустая строка не работает и должна быть null.
Примечание 2. это исправление работает с использованием чистого JavaScript (но не с методом jquery .attr). После того, как я опубликовал это решение, я попробовал его с помощью метода jquery .attr, установив для него значение $img.attr('src', null);, но это не сработало, и когда я изменил его на javascript, это сработало. Я также попробовал это, используя метод jquery .prop вместо этого, как $img.prop('src', null);, который работал в первый раз и терпел неудачу при нескольких последующих обновлениях. Только чистый javascript кажется верным решением.

ОБНОВЛЕНИЕ:
Хорошо, оказалось, что, хотя вышеуказанное изменение исправляет Chrome и заставляет его неоднократно вызывать onerror, как и все другие браузеры (FF, Safari, Opera, IE7-9), оно вызывает проблемы. с событием onerror для IE10 и, таким образом, игнорирует любые допустимые изображения, назначенные src после установки его на =null в предыдущей строке. (...вздох).

person johntrepreneur    schedule 14.07.2013
comment
Вы можете угодить НЕКОТОРЫМ браузерам ВСЕ время, Вы можете угодить ВСЕМ браузерам НЕКОТОРЫМ время, но вы не можете угодить ВСЕМ браузерам ВСЕМ время. - person johntrepreneur; 18.07.2013
comment
ответ Джесса надежно работает во всех браузерах (хотя его jsfiddle не работает) и даже не является взломом - вы должны принять его вместо этого, так как ваш делает дополнительные запросы... - person Nikola Bogdanović; 31.12.2013

Это правильное поведение. Вы не хотите загружать одно и то же изображение дважды — это пустая трата полосы пропускания.

Что Chrome создает объект в памяти, а затем применяет его ко всем изображениям с соответствующим src.

Если вам нужно загрузить его дважды, создайте эти объекты с помощью javascript и назначьте .onload=function() { .. } каждому.

person Mikhail    schedule 14.07.2013
comment
он ничего не загружает дважды. В скрипте, когда начальное изображение в атрибуте src не найдено, он запускает событие onerror, которое изменяет атрибут src элемента img на новый URL-адрес. Когда новый URL-адрес повторно оценивается и снова определяется как 404, он должен снова вызывать событие onerror, пока вы не разыменуете его с помощью onerror = ''. Как и все остальные браузеры. Попробуйте скрипку в Chrome, а также в другом браузере. - person johntrepreneur; 14.07.2013

Я думаю, что @Mikhail на правильном пути, за исключением немного другой причины. Во втором примере вы пытаетесь загрузить 2 изображения с одного и того же несуществующего домена www.asdfjklasdfasdf.com.

При попытке загрузить bogus1.png Chrome не может преобразовать домен в IP-адрес.

При попытке загрузить bogus2.png (из того же несуществующего домена) Chrome вообще ничего не делает... потому что знает, что поиск домена не удался. Вопрос о том, является ли правильным поведение Chrome не отправлять другое событие onerror, может быть открытым :) Я ожидаю, что так и должно быть.

Чтобы доказать это, просто добавьте 1 символ к имени домена для bogus2.png, и оно будет работать так, как вы ожидали.

Изменить

Один из способов, которым вы можете заставить его попытаться выполнить последующие загрузки, — изменить src в <img> на пустую строку. Это немного хакерски, но это работает. Вы можете установить для атрибута rsrc что-то вроде этого:

rsrc="''|http://www.asdfjklasdfasdf.com/bogus2.png|''|http://eatfrenzy.com/images/success-tick.png"

Таким образом, при возникновении ошибки вы устанавливаете источник ''. Кажется, это тоже вызывает ошибку, которая затем запускает попытку следующего источника...

person Sunil D.    schedule 14.07.2013
comment
Блэрг! Я думаю, что мое редактирование было ошибочным. Ваш оригинальный пример работает для меня сейчас, когда раньше не работал. - person Sunil D.; 14.07.2013
comment
вы к чему-то пришли, предложив установить для атрибута src пустую строку между вызовами onerror. Кажется, он работает в Chrome таким образом и продолжает неоднократно вызывать его, но не уверен, почему. - person johntrepreneur; 14.07.2013
comment
интересный момент насчет домена, но не из-за этого он выручает. Я изменил скрипт выше, чтобы использовать то же доменное имя только с поддельным именем файла, и проблема все еще существует. - person johntrepreneur; 14.07.2013

Как ответил Etdashou на этот вопрос: https://stackoverflow.com/a/9891041/1090274, настройка this.onerror=null; работала для меня.

person Dany Gauthier    schedule 31.03.2015