¿Debería estar disponible la configuración de una imagen SRC en la URL de datos?
-
23-10-2019 - |
Pregunta
Considere el siguiente código JavaScript (frágil):
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!'); };
Las preguntas)
- ¿Debería el ancho de la imagen y la altura ser correctos de inmediato?
- ¿Debería el lienzo dibujar funcionar de inmediato?
- Si el
onload
¿Se invoca la devolución de llamada (establecida después de que se cambió el SRC)?
Pruebas experimentales
Creé un Página de prueba simple con código similar. En Safari, mis primeras pruebas, ambas abriendo la página HTML localmente (file:///
url) y cargarlo desde mi servidor, mostró todo funcionando: la altura y el ancho son correctos, el dibujo de lienzo funciona, y la onload
también incendios.
En Firefox v3.6 (OS X), cargar la página después de iniciar el navegador muestra que la altura/ancho no es correcta inmediatamente después de la configuración, drawImage()
falla. (Los onload
Sin embargo, el manejador se dispara). Sin embargo, la carga de la página muestra que el ancho/altura es correcta inmediatamente después de la configuración, y drawImage()
laboral. Parece que Firefox almacena el contenido de la URL de datos como una imagen y la tiene disponible de inmediato cuando se usa en la misma sesión.
En Chrome V8 (OS X) veo los mismos resultados que en Firefox: la imagen no está disponible de inmediato, pero toma algún tiempo 'cargar' asincrónicamente de la URL de datos.
Además de la prueba experimental de lo que los navegadores hacen o no funcionan, realmente me encantan los enlaces a las especificaciones sobre cómo se supone que esto se comporta. Hasta ahora, mi Google-Fu no ha estado a la altura de la tarea.
Jugando a salvo
Para aquellos que no entienden por qué lo anterior podría ser peligroso, sepa que debe usar imágenes como esta para estar a salvo:
// 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 = '...';
Solución
Como nadie ha encontrado ninguna especie sobre cómo es esto supuesto Para comportarse, tendremos que estar satisfechos con cómo lo hace comportarse. Los siguientes son los resultados de mis pruebas.
| 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** ------------+-----------------------------+-------------------------------------
En resumen:
- No puede asumir que los datos de la imagen estarán disponibles justo después de configurar un Data-URI; Debes esperar el
onload
evento. - Debido a IE9, no puedes establecer el
onload
manejador después de configurar elsrc
y espere que se invoque. - Las recomendaciones en "Jugando a salvo" (De la pregunta anterior) son la única forma de garantizar un comportamiento correcto.
Si alguien puede encontrar especificaciones discutiendo esto, felizmente aceptaré su respuesta.
Otros consejos
Después de devolver el control al motor de representación del navegador, la prueba informa true
En FF 4B9 y Chromium 8.0.552.237. Modifiqué estas piezas:
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);
Actualizar: Sí, entiendo que esta 'respuesta' es más como un comentario, pero solo quería señalarlo. Y después de las pruebas obtengo resultados reproducibles:
- sin que
setTimeout
, en ambos navegadores obtengofalse
la primera vez que abre la página ytrue
Solo después de golpear F5. Después de limpiar explícitamente el caché, ambos dicenfalse
nuevamente después de recargar. - con
setTimeout
La prueba de ancho/altura siempre se evala atrue
.
En ambos casos, la imagen no aparece la primera vez, solo después de recargar la página.