Sollte das Festlegen eines Bild -SRC auf Daten -URL sofort verfügbar sein?
-
23-10-2019 - |
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 = '...';
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 dersrc
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 ichfalse
Das erste Mal öffne ich die Seite undtrue
Erst nach dem Schlagen F5. Nachdem sie den Cache explizit gelöscht haben, sagen beidefalse
Wieder nach dem Nachladen. - mit
setTimeout
Der Breiten-/Höhentest evualuiert immer zutrue
.
In beiden Fällen wird das Bild nicht zum ersten Mal angezeigt, erst nach dem Nachladen der Seite.