Должна ли установка изображения 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 ответа:
как никто еще не нашел никаких спецификаций о том, как это должно чтобы вести себя, нам придется довольствоваться тем, как это тут веди себя прилично. Ниже приведены результаты моих тестов.
| 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
.в обоих случаях изображение не появляется в первый раз, только после перезагрузки страницы.