2011-01-23 6 views
69

Considere lo siguiente (frágil) código JavaScript:¿Debería estar disponible la configuración de una imagen src a la URL de datos disponible de inmediato?

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!'); }; 

La Pregunta (s)

  • caso de que el ancho de la imagen y la altura correcta de inmediato?
  • ¿Debería dibujar el lienzo de inmediato?
  • ¿Debería invocarse la devolución de llamada onload (establecida después de que se cambió el src)?

pruebas experimentales
he creado un simple test page con un código similar. En Safari mis primeras pruebas, tanto mediante la apertura de la página HTML localmente (file:/// url) y cargarlo desde mi servidor, mostraron todo funcionando: la altura y la anchura es correcta, el lienzo dibujan las obras, y la onload incendios también.

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 onload se activa). 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 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.

Apostar sobre seguro
Para aquellos que no entienden por qué lo anterior podría ser peligroso, sabe que debe usar imágenes como ésta sea segura:

// 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 = '...'; 
+1

Definitivamente debe configurar 'on' antes de configurar' src'. Pero si el evento de carga a veces se activa en la constelación actual, entonces establecer el URI de "datos" es ciertamente asíncrono, lo que me sorprendería. ¡Interesante! –

+0

¿No es más seguro suponer que no, para aumentar el tiempo de espera y continuar después de que el navegador tenga la posibilidad de volver a dibujarse? –

+0

@mP Sí, ciertamente lo es; Edité mi pregunta para aclarar esto unos 5 minutos antes de su comentario :) Sin embargo, esto no invalida la pregunta. Suponiendo que el comportamiento en Chrome y FF es permisible, no es un error, entonces, es vital, de hecho, ir a lo seguro. – Phrogz

Respuesta

51

Como hasta ahora nadie ha encontrado ninguna especificación acerca de cómo esto es supone comportarse, tendremos que estar satisfechos con la forma en que lo hace se comportan. 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 se puede asumir que los datos de las imágenes estarán disponibles inmediatamente después de establecer una técnica de URI; debe esperar el evento onload.
  • Debido a IE9, no puede establecer el controlador onload después de configurar el src y esperar que se invoque.
  • Las recomendaciones en "Jugar seguro" (de la pregunta anterior) son la única manera de garantizar el comportamiento correcto.

Si alguien puede encontrar especificaciones discutiendo esto, con gusto aceptaré su respuesta.

+3

Gracias por la investigación que hizo aquí. He estado luchando con la posibilidad de forzar este comportamiento para una aplicación web fuera de línea en la que necesito informar usando canvas, así que profundicé un poco más. La especificación WHATWG viviente realmente llama al caso almacenado en caché como sincrónico, y el caso no cacheado como asíncrono. Consulte el paso 7 en la sección src de la especificación que se encuentra aquí: http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#attr-img-src. Parece que si la imagen está en la "lista de imágenes disponibles" del documento, se completa de forma sincrónica, o así es como la leo. –

+0

@Phrogz ¿En qué etapa o estado del documento realizó esa prueba? Estoy observando Safari 5.1 para tener el comportamiento de Chrome, pero eso es antes del evento 'window.load'. ¿Sus pruebas fueron hechas después de la carga o antes? ¿Te acuerdas? – hexalys

6

Después de dar el control al motor de renderizado del navegador, los informes de prueba true en FF 4b9 y Chromium 8.0.552.237. He modificado las siguientes 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 esta 'respuesta' es más como un comentario, pero sólo quería señalarlo. Y después de la prueba consigo resultados reproducibles:

  • sin setTimeout, en ambos navegadores que recibo false la primera vez que abra la página y true sólo después de golpear F5 . Después de borrar explícitamente la caché, ambos dicen false nuevamente después de volver a cargar.
  • con setTimeout la prueba de ancho/alto siempre indica true.

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

+0

¿Me está diciendo que sin estos cambios está viendo 'fallas' en FF y Chromium? Mi pregunta no es cómo hacer que esto funcione, ya que establece claramente 'onload' antes de 'src' y solo funcionará la referencia a la imagen en la devolución de llamada. Mi pregunta es si existen especificaciones que describan cómo debería funcionar esto. – Phrogz

Cuestiones relacionadas