javascript - etiqueta - img src url
¿Debería estar disponible la configuración de una imagen src a la URL de datos de inmediato? (2)
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)
- ¿El ancho y la altura de la imagen deben ser correctos de inmediato?
- ¿Debería dibujar el lienzo de inmediato?
- ¿Debería
onload
devolución de llamada deonload
(establecida después de que se cambió el src)?
Pruebas experimentales
Creé una página de prueba simple con código similar. En Safari, mis primeras pruebas, tanto al abrir la página HTML localmente ( file:///
url) y cargarla desde mi servidor, todo se mostró: el alto y el ancho son correctos, el lienzo funciona y la carga también se activa.
En Firefox v3.6 (OS X), cargar la página después de iniciar el navegador muestra que el alto / ancho no es correcto inmediatamente después de la configuración, drawImage()
falla. (Sin embargo, el controlador de carga se drawImage()
. Sin embargo, al volver a cargar la página, se muestra que el ancho / alto es correcto inmediatamente después de la configuración y que drawImage()
funciona. Parece que Firefox guarda en caché 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 un tiempo para ''cargarse'' asincrónicamente desde la URL de datos.
Además de la prueba experimental de qué navegadores funciona o no, me encantan los enlaces a las especificaciones sobre cómo se supone que debe comportarse. Hasta ahora, mi Google-fu no ha estado a la altura de la tarea.
Jugando a lo seguro
Para aquellos que no entienden por qué lo anterior puede ser peligroso, sepa que debe usar imágenes como esta para estar seguro:
// 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 = ''...'';
Como nadie ha encontrado aún especificaciones sobre cómo se supone que debe comportarse, tendremos que estar satisfechos con cómo se comporta. 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 suponer que los datos de la imagen estarán disponibles justo después de configurar un uri de datos; debes esperar el evento de
onload
. - Debido a IE9, no puede configurar el controlador de
onload
después de configurar elsrc
y esperar que se invoque. - Las recomendaciones de "Jugar seguro" (de la pregunta anterior) son la única forma de garantizar un comportamiento correcto.
Si alguien puede encontrar especificaciones discutiendo esto, aceptaré felizmente su respuesta.
Después de devolver el control al motor de representación del navegador, los informes de prueba son true
en FF 4b9 y Chromium 8.0.552.237. Modifiqué estas partes:
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);
Actualización: 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
setTimeout
, en ambos buscadores consigofalse
la primera vez que abro la página y solo después de presionar F5 . Después de borrar explícitamente la memoria caché, ambos dicen "false
nuevamente después de volver a cargar. - con
setTimeout
la prueba de ancho / alto siempre se verifica comotrue
.
En ambos casos, la imagen no aparece la primera vez, solo después de volver a cargar la página.