Должен ли настройка изображения SRC на URL -адрес данных быть немедленно доступным?

StackOverflow https://stackoverflow.com/questions/4776670

Вопрос

Рассмотрим следующий (хрупкий) код JavaScript:

var img = new Image;
img.src = "data:image/png;base64,..."; // Assume valid data

// Danger(?) Attempting to use image immediately after setting src
console.log( img.width, img.height );
someCanvasContext.drawImage( img, 0, 0 );

// Danger(?) Setting onload after setting src
img.onload = function(){ console.log('I ran!'); };

Вопросы)

  • Должны ли ширина и высота изображения быть немедленно верны?
  • Должен ли холст нарисовать немедленно работать?
  • Должен onload обратный вызов (установлен после того, как SRC был изменен) быть вызванным?

Экспериментальные тесты
Я создал Простая тестовая страница с аналогичным кодом. В Safari мои первые тесты, оба от открытия HTML -страницы локально (file:/// URL) и загрузка его с моего сервера, показал все, что работает: высота и ширина верны, рисунок холста работает, а также а onload также пожары.

В Firefox v3.6 (OS X) загрузка страницы после запуска браузера показывает, что высота/ширина не верна сразу после настройки, drawImage() терпит неудачу. ( onload Хэндлер, однако, стреляет.) Однако загрузка страницы снова показывает, что ширина/высота верна сразу после настройки, и drawImage() работающий. Похоже, что Firefox кэширует содержимое URL данных в качестве изображения и имеет его немедленно при использовании в том же сеансе.

В Chrome V8 (OS X) я вижу те же результаты, что и в Firefox: изображение не доступно немедленно, но требует некоторого времени для асинхронной «загрузки» из URL -адреса данных.

В дополнение к экспериментальному доказательству того, что браузеры, вышеупомянутые, делают или не работают, я бы очень хотел ссылки на характеристики о том, как это должно вести себя. До сих пор мой Google-Fu не выполнил задачу.

Играя в безопасное место
Для тех, кто не понимает, почему вышесказанное может быть опасным, знайте, что вам следует использовать такие изображения, чтобы быть в безопасности:

// First create/find the image
var img = new Image;

// Then, set the onload handler
img.onload = function(){
  // Use the for-sure-loaded img here
};

// THEN, set the src
img.src = '...';
Это было полезно?

Решение

Поскольку никто еще не нашел каких -либо спецификаций о том, как это предполагаемый Чтобы вести себя, мы должны быть удовлетворены тем, как это делает вести себя. Ниже приведены результаты моих тестов.

            | is image data usable right  | does onload callback set after src
            |     after setting src?      |   is changed still get invoked?
------------+-----------------------------+-------------------------------------
Safari  5   |             yes             |                  yes                
------------+-----------------------------+-------------------------------------
Chrome  8   | **no** (1st page load), but |                  yes                
FireFox 3.6 |  yes thereafter (cached)    |                                     
------------+-----------------------------+-------------------------------------
IE8         |    yes (32kB data limit)    |                  yes         
------------+-----------------------------+-------------------------------------
IE9b        |             yes             |                 **no**              
------------+-----------------------------+-------------------------------------

В итоге:

  • Вы не можете предположить, что данные изображения будут доступны сразу после настройки Data-URI; Вы должны ждать onload мероприятие.
  • Из -за IE9 вы не можете установить onload обработчик после установки src И ожидайте, что это будет вызвано.
  • Рекомендации в "Играй в безопасном месте" (Из задания выше) - единственный способ обеспечить правильное поведение.

Если кто -то сможет найти спецификации, обсуждающие это, я с радостью приму их ответ.

Другие советы

После возвращения контроля в двигатель рендеринга браузера сообщает true В FF 4B9 и Chromium 8.0.552.237. Я изменил эти части:

img.onload = function(){   // put this above img.src = …
    document.getElementById('onload').innerHTML = 'yes';
};
img.src = img_src;
…
window.setTimeout(function () {   // put this inside setTimeout
    document.getElementById('wh').innerHTML = (img.height==img.width) && (img.height==128);
}, 0);

Обновлять: Да, я понимаю, что этот «ответ» больше похож на комментарий, но просто хотел указать на него. И после тестирования я получаю воспроизводимые результаты:

  • без setTimeout, в обоих браузерах я получаю false В первый раз, когда я открываю страницу и true Только после удара F5. Анкет После явного очистки кэша говорят, что оба говорят false снова после перезагрузки.
  • с setTimeout тест на ширину/высоту всегда направляется к true.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top