Frage

Betrachten Sie den folgenden (fragilen) JavaScript -Code:

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

Die Fragen)

  • Sollte die Bildbreite und Höhe sofort korrekt sein?
  • Sollte die Leinwand sofort arbeiten?
  • Sollte die onload Rückruf (gesetzt, nachdem die SRC geändert wurde) aufgerufen werden?

Experimentelle Tests
Ich habe a erstellt Einfache Testseite mit ähnlichem Code. In Safari meine ersten Tests, beide durch Öffnen der HTML -Seite lokal (file:/// URL) und laden Sie es von meinem Server, zeigte alles, was funktioniert: Die Höhe und Breite ist korrekt, die Leinwand zeichnet funktioniert, und das onload Auch Feuer.

In Firefox V3.6 (OS X) zeigt das Laden der Seite nach dem Start des Browsers, dass die Höhe/Breite unmittelbar nach der Einstellung nicht korrekt ist. drawImage() scheitert. (Das onload Handler feuert jedoch jedoch.) Das Laden der Seite zeigt jedoch erneut, dass die Breite/Höhe unmittelbar nach der Einstellung korrekt ist und und drawImage() Arbeiten. Es scheint, dass Firefox den Inhalt der Daten -URL als Bild zwischenspeichert und sie sofort verfügbar ist, wenn sie in derselben Sitzung verwendet werden.

In Chrome V8 (OS X) sehe ich die gleichen Ergebnisse wie in Firefox: Das Bild ist nicht sofort verfügbar, dauert jedoch einige Zeit, bis asynchron "last" aus der Daten -URL.

Zusätzlich zum experimentellen Beweis dafür, was Browser die oben genannten Funktionen funktionieren oder nicht, würde ich Links zu Spezifikationen darüber sehr lieben, wie sich dies verhalten soll. Bisher war mein Google-Fu nicht der Aufgabe.

Auf Nummer sicher gehen
Für diejenigen, die nicht verstehen, warum das oben genannte gefährlich sein könnte, wissen Sie, dass Sie solche Bilder verwenden sollten, um sicher zu sein:

// 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 = '...';
War es hilfreich?

Lösung

Da hat noch niemand Spezifikationen darüber gefunden, wie dies ist soll Um uns zu verhalten, müssen wir uns damit zufrieden geben, wie es tut sich verhalten. Im Folgenden sind die Ergebnisse meiner Tests aufgeführt.

            | 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**              
------------+-----------------------------+-------------------------------------

Zusammenfassend:

  • Sie können nicht davon ausgehen, dass die Bilddaten gleich nach dem Einstellen eines Daten-URI verfügbar sind. Sie müssen auf die warten onload Veranstaltung.
  • Aufgrund von IE9 können Sie das nicht einstellen onload Handler nach dem Einstellen der src und erwarten Sie, dass es angerufen wird.
  • Die Empfehlungen in "Auf Nummer sicher" (aus der obigen Frage) sind der einzige Weg, um ein korrektes Verhalten zu gewährleisten.

Wenn jemand Spezifikationen finden kann, die darüber diskutieren, werde ich stattdessen seine Antwort gerne annehmen.

Andere Tipps

Nachdem die Testmotor die Kontrolle über den Browser -Rendering -Motor zurückgelegt haben, berichtet die Testberichte true in FF 4B9 und Chrom 8.0.552.237. Ich habe diese Teile geändert:

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);

Aktualisieren: Ja, ich verstehe, dass diese "Antwort" eher ein Kommentar ist, wollte aber nur darauf hinweisen. Und nach dem Testen bekomme ich reproduzierbare Ergebnisse:

  • ohne setTimeout, In beiden Browsern bekomme ich false Das erste Mal öffne ich die Seite und true Erst nach dem Schlagen F5. Nachdem sie den Cache explizit gelöscht haben, sagen beide false Wieder nach dem Nachladen.
  • mit setTimeout Der Breiten-/Höhentest evualuiert immer zu true.

In beiden Fällen wird das Bild nicht zum ersten Mal angezeigt, erst nach dem Nachladen der Seite.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top