Ожидание загрузки изображения в JavaScript

Я делаю вызов Ajax, который возвращает мне некоторую информацию, включая путь к изображению.

Я готовлю всю эту информацию в своем HTML, который будет отображаться в виде всплывающего окна. Я просто переключаю видимость всплывающего div со скрытого на видимый.

Чтобы установить позицию моего всплывающего div, мне нужно вычислить в зависимости от высоты изображения. Итак, мне нужно дождаться загрузки изображения, чтобы узнать его размер, прежде чем устанавливать положение и переключать видимость на видимую.

Я пробовал трюки с рекурсией, setTimeout, complete img property, while loop ... безуспешно.

Итак, как я могу это сделать? Возможно, мне следует вернуть размеры в моем вызове Ajax.


person Jeenyus    schedule 26.02.2010    source источник
comment
почему не работает со свойством Image.complete?   -  person Otto Allmendinger    schedule 26.02.2010


Ответы (6)


var img = new Image();
img.onload = function() { alert("Height: " + this.height); }
img.src = "http://path/to/image.jpg";

Обратите внимание, что это важно делать в указанном выше порядке: Сначала прикрепите обработчик, затем установите src. Если вы сделаете наоборот, а изображение находится в кеше, вы можете пропустить событие. В браузерах JavaScript выполняется в одном потоке (если вы не используете веб-воркеры), но браузеры не являются однопоточными. Совершенно верно, что браузер видит src, определяет, что ресурс доступен, загружает его, запускает событие, просматривает элемент, чтобы увидеть, есть ли у него какие-либо обработчики, которые должны быть поставлены в очередь для обратного вызова, не видеть их, и завершить обработка событий, все между строкой src и строкой, присоединяющей обработчик. (Обратные вызовы не происходили бы между строками, если бы они были зарегистрированы, они бы ждали в очереди, но если их нет, событие не должно ждать.)

person Josh Stodola    schedule 26.02.2010
comment
Grat! Кстати: я совершенно не разбираюсь в теме AJAX, но на всякий случай, если изображение, полученное с помощью AJAX, кэшируется так же, как изображение, непосредственно записанное в HTML-код, вы можете в конечном итоге добавить это, чтобы избежать кеширования изображений в браузере (очевидно, только если он вам нужен): img.src = путь / к / image.jpg +? refresh = + новый Date (). getTime (); - person Marco Demaio; 26.02.2010
comment
@Marco Или установите cache: false на XHR :) Хотя я не думаю, что здесь это актуально, потому что вызов AJAX возвращает URL-адрес изображения, а не само изображение. Но да, я полагаю, он все еще мог бы использовать случайное значение строки запроса, чтобы убедиться, что кеширование пользовательского агента не происходит. - person Josh Stodola; 26.02.2010
comment
Можете ли вы добавить прослушиватель событий или заменяет onload способом? - person IQAndreas; 09.04.2014
comment
@IQAndreas: Ты мог бы использовать img.addEventListener("load", ...), да. (Или img.attachEvent("onload", ...) в старом IE). - person T.J. Crowder; 17.08.2015
comment
Имеет ли значение, если я изменю порядок второй и третьей строки? - person Ali Sheikhpour; 02.09.2019
comment
На самом деле это не отвечает на вопрос: как дождаться загрузки изображения (очевидно, в текущем потоке). - person Arkady; 20.04.2020
comment
Могу ли я сделать это без создания элемента изображения из Javascript? - person gyozo kudor; 22.06.2021

Если вы используете jQuery, вы можете использовать его событие load.

Взгляните на пример:

$('img.userIcon').load(function(){
    if($(this).height() > 100) {
        $(this).addClass('bigImg');
    }
});
person Sagi    schedule 26.02.2010
comment
-1: в вопросе нет упоминания о jQuery, поэтому такой ответ может сбивать с толку. - person Andy E; 26.02.2010
comment
Пожалуйста, не используйте jquery, если не запрошен jquery - person Juan Mendes; 26.02.2010
comment
Также обратите внимание на следующие предостережения в отношении метода загрузки при использовании с изображениями (взяты из api.jquery.com/ load-event): ›Он не работает ни согласованно, ни надежно кроссбраузерно› Он не запускается правильно в WebKit, если src изображения установлен на тот же src, что и раньше ›Он не всплывает правильно дерево DOM ›Может перестать работать для изображений, которые уже находятся в кеше браузера. - person Rich O'Kelly; 11.12.2013

просто оберните загрузку изображения в функцию с обещанием, а затем вызовите ее с помощью await.

async drawImg(ctx, image){

    return new Promise(resolve => {

          image.onload = function () {
                ctx.drawImage(image, 10, 10, 200, 180);
                resolve('resolved');
             }

    });

  }

он должен работать нормально

person amara mohamed amine    schedule 02.03.2020
comment
Ключевое слово async здесь не нужно - достаточно вернуть обещание, чтобы вызывающий await его. Также рекомендуется назначить обработчик ошибок reject(), чтобы вызывающий мог поймать ошибку в случае сбоя загрузки. Последнее предложение: вы можете передать сам объект изображения в resolve(this), чтобы вызывающий мог рисовать изображение или делать с ним все, что хочет. - person ggorlen; 13.02.2021

принятый ответ устарел, но показывает базовый _ 1_ обратный вызов. В настоящее время вы, вероятно, захотите обещать загрузку изображения, чтобы избежать ада обратных вызовов.

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

Вот еще одно обещание Image, более общее. Отказ в обработчике onerror и передача фактического объекта изображения в преобразователь важны для того, чтобы сделать функцию минимально пригодной для повторного использования.

Улучшения могут включать дополнительные параметры (например, crossOrigin). Объект settings или предоставление Image в качестве параметра - это еще один подход к обобщению функции (установка src запускает запрос, поэтому он должен идти последним после добавления обработчиков).

const loadImage = src =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  })  
;

loadImage("http://placekitten.com/90/100").then(image => 
  console.log(image, `\nloaded? ${image.complete}`)
);

С помощью указанной выше функции Promise.all может использоваться для параллельной загрузки пакета изображений ( Promise.allSettled полезно, если вы хотите продолжить, даже если некоторые изображения не загружаются).

const loadImage = src =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  })  
;

const imageUrls = [
  "http://placekitten.com/85/150",
  "http://placekitten.com/85/130",
  "http://placekitten.com/85/110",
];
Promise.all(imageUrls.map(loadImage)).then(images => {
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  const ctx = canvas.getContext("2d");
  images.forEach((image, i) =>
    ctx.drawImage(image, i * 90, 0, image.width, image.height)
  );
});

person ggorlen    schedule 13.02.2021

Как насчет события загрузки окна?

window.addEventListener('load', (event) => {
  //do stuff with images
});

or

window.onload = (event) => {
  //do stuff with images
};

https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

Это сработало для меня, когда мне нужно было, чтобы браузер вычислял размер изображений перед запуском сценария макета.

person Billy Mitchell    schedule 30.03.2021
comment
Это не совсем похоже на ответ на вопрос, так как изображение может загружаться после загрузки самой страницы много раз, включая этот пример. Событие onload в окне действительно ожидает загрузки изображений, но только для начальной загрузки страницы. В контексте этого вопроса событие onload должно быть привязано непосредственно к загружаемому элементу изображения. - person Joseph; 30.03.2021

У меня была медленная загрузка изображения CAPTCHA (1st_image) на моей странице, и я хотел отобразить другое изображение (2nd_image) только ПОСЛЕ загрузки изображения CAPTCHA (1st_image). Поэтому мне пришлось дождаться загрузки изображения CAPTCHA (1st_image).

Вот решение, которое отлично работает, когда сначала загружается изображение, а затем загружается другое изображение (не забудьте отобразить изображение «пожалуйста, подождите!», Пока они ждут загрузки другого изображения):

<script>
    function checkImageLoad() {
        if (document.getElementById("1st_image").complete == true) {
            console.log("1st_image Loaded!");
        }
        document.getElementById("2nd_image").src = "http://example.org/2nd_image.png";
    }
</script>
<body onload="checkImageLoad();">
<img id="1st_image" src="http://example.org/1st_image.png">
<img id="2nd_image" src="http://example.org/loading_please_wait.gif">

Либо скорость Интернета низкая, либо высокая, и браузер будет ждать, пока вся страница загрузится со всеми изображениями (даже если они связаны внешними ссылками), а затем выполнит функцию, поэтому второе изображение отображается только после загрузки первого изображения. отлично.

Дополнительное примечание: вы можете использовать URL-адрес веб-страницы в src изображения, чтобы сначала загрузить веб-страницу, а затем показать изображение. Цель состоит в том, чтобы загрузить файл cookie с внешней веб-страницы, который может повлиять на отображаемое второе изображение (например, CAPTCHA).

person Tarik    schedule 01.05.2016