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 = '...';
¿Fue útil?

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 el src 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 obtengo false la primera vez que abre la página y true Solo después de golpear F5. Después de limpiar explícitamente el caché, ambos dicen false nuevamente después de recargar.
  • con setTimeout La prueba de ancho/altura siempre se evala a true.

En ambos casos, la imagen no aparece la primera vez, solo después de recargar la página.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top