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


рассмотрим следующий (хрупкий) код 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) и загрузив его с моего сервера, показал все, что работает: высота и ширина правильная, холст рисовать работает,и the 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 = '...';
2 69

2 ответа:

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

            | 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 и Хроме 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 тест ширины/высоты всегда evualuates к true.

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