Должен ли настройка изображения SRC на URL -адрес данных быть немедленно доступным?
-
23-10-2019 - |
Вопрос
Рассмотрим следующий (хрупкий) код 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
.
В обоих случаях изображение не отображается в первый раз, только после перезагрузки страницы.