Warten bis image geladen ist - Druckversion +- Javascript-forum (https://javascript-forum.de) +-- Forum: Entwicklung (https://javascript-forum.de/forumdisplay.php?fid=4) +--- Forum: Javascript (https://javascript-forum.de/forumdisplay.php?fid=6) +--- Thema: Warten bis image geladen ist (/showthread.php?tid=2729) |
Warten bis image geladen ist - mike64 - 17.01.2024 Hallo es sollte einfach sein, aber es ist wohl ein bekanntes Problem mit dem asynchronen Laden eines images Mein Problem ist, daß ich ähnlich einer VCL Objekte erzeuge, die in Canvas grafisch dargestellt werden, ihrerseits buttons enthalten usw. Das klappt auch alles ganz gut, solange die darzustellenden Bilder geladen sind. Lege ich ein Objekt an, wird das Bild geladen und ich benötige bereits in der nächsten Zeile die Bilddaten, die aber noch nicht zur Verfügung stehen. Weitere Objekte hängen dann von diesem Objekt ab, ich kann es also nicht asynchron programmieren Der Versuch auf das Bild zu warten scheitert an der Endlosschleife, hier mal mit ausgeklammertem Timeout. Die Bedingung wird nie erfüllt, auch nicht wenn ich auf image.height!=0 teste. Ich vermute mal, daß in der Schleife zumindestens mal so etwas wie processmessages stehen muß, damit andere Arbeiten weiter gehen? Wer weiß Rat? Code: function loadImg (img_url) RE: Warten bis image geladen ist - Sempervivum - 17.01.2024 Hallo, Zitat:Weitere Objekte hängen dann von diesem Objekt ab, ich kann es also nicht asynchron programmieren "geht nicht gibt's nicht", aber von Anfang an: Du hast vollkommen Recht, mit diesem Problem ist jeder konfrontiert, der Bilder lädt und bei der weiteren Verarbeitung darauf an gewiesen ist, dass sie fertig geladen sind. Das Verfahren mit der Schleife ist machbar, es gibt da eine Eigenschaft, die angibt ob das Bild vollständig geladen ist: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete Aber auf der anderen Seite nicht sehr elegant, es gibt bessere. Einfachste Möglichkeit: Die weitere Verarbeitung vom load-Event abhängig machen, etwa so: Code: const image = new Image(); Großer Nachteil dabei: Das Ganze wird unübersichtlich verschachtelt, wenn man auf mehrere Bilder warten muss. Alternative für mehrere Bilder: Eine Funktion definieren, die bei jedem load aufgerufen wird und einen Zähler erhöht, der die geladenen Bilder zählt. Hat dieser die Anzahl der zu ladenden Bilder erreicht, wird die weitere Verarbeitung gestartet. Zitat:Lege ich ein Objekt an, wird das Bild geladen und ich benötige bereits in der nächsten Zeile die Bilddaten, die aber noch nicht zur Verfügung stehen. Auch das ist machbar, wenn Du das Verfahren async - await anwendest. Setzt allerdings voraus, dass sich alles in einer async-Funktion abspielt und wird z. B. hier beschrieben: https://www.fabiofranchino.com/log/load-an-image-with-javascript-using-await/ Ich kenne aber keine Möglichkeit, die nicht von einer kapselnden Funktion abhängig ist. Wenn man mal von dem veralteten XMLHttpRequest absieht, wo man auf synchrone Verarbeitung umschalten kann. Davon raten aber alle verlässlichen Quellen ab. RE: Warten bis image geladen ist - mike64 - 19.01.2024 Danke für die Ausführungen leider komme ich nicht weiter 1) Die Abfrage per Schleife scheitert daran, daß ich mich immer in eine Endlosschleife begebe, was den Browser zum Absturz bringt. Das Ereignis tritt nie ein. Ich vermute, der Interpreter führt da keine weiteren Arbeiten aus, sodaß die Variable irgendwann mal geändert wird und die Schleife verlassen wird. Weder mit complete, noch mit flags. 2) Der Versuch mit await scheitert auch. Ich habe es so verstanden, daß await hier wirklich wartet, muß aber feststellen, daß mein Hauptprogramm weiter läuft. Gemäß dem Beispiel habe ich meine Prozeduren mit await geschrieben und sehe in der Konsole zahlreiche Bildanforderungen und irgendwann kommt dann mal die ein oder andere "Geladen" Meldung. Somit wartet das Programm hier nicht sondern arbeitet weiter. Nur die Async Funktion wartet. Dann wäre das nur eine andere Programmierung bei sonst gleicher Problematik. Ich benötige ein echtes Stop und bekomme es nicht hin. Code: function loadImage (path) RE: Warten bis image geladen ist - Sempervivum - 19.01.2024 Ich schrieb ja schon: Zitat:Ich kenne aber keine Möglichkeit, die nicht von einer kapselnden Funktion abhängig ist.Bei asynchronen Vorgängen kommst Du nicht daran vorbei, die Bearbeitung in eine Funktion hinein zu schreiben. Ich sehe aber keinen Grund, warum das nicht machbar sein sollte. async-await hat nur den Vorteil, dass Du keine Verschachtelungen bekommst. Code: async function loadImg (img_url) RE: Warten bis image geladen ist - mike64 - 19.01.2024 Ok, aber jetzt setze ich noch einen drauf: Ich habe mal eine Warteschleife in der aufrufenden Prozedur probiert zuvor werden rund 30 Icons mit Loadimage geladen Der Zähler erhöht sich erwartungsgemäß mit jedem Aufruf des Constructors, wird aber niemals niedriger. Dagegen wird der Zähler niedriger sobald Arbeiten erledigt sind. Anscheinend, sobald der Browser Freizeit hat. Somit habe ich mein Problem mit der Endlosschleife wenn ich auf imgreq==0 teste. Das würde bedeuten, daß ich die Anwendung ähnlich einer Interruptroutine komplett ereignisgesteuert programmieren muß. Also eine Befehlswarteschlange die von zahlrreichen Loadimg getriggert ist (das kann es doch nicht sein) Jetzt könnte ich natürlich erst das image laden und den Device constructor mit onload aufrufen, würde für die einzelnen Objekte funktionieren Dann hänge ich spätestens bei drawcanvas wieder in der Situation, daß ich prüfen muß ob alles geladen ist und da ist sie wieder, meine nie erfüllte Endlosschleife. Aufrufende Prozedur (Erstellung eines Objekts) Code: class TDevice Loadimage mit Zähler Code: function loadImg (img_url) RE: Warten bis image geladen ist - Sempervivum - 19.01.2024 Nein, keine Endlosschleife. Ich meinte das so: Code: const imgUrls = ['images/dia0.jpg', 'images/dia1.jpg', 'images/dia2.jpg']; Und mit async-await: Code: async function loadImages() { RE: Warten bis image geladen ist - mike64 - 19.01.2024 Ok vielen Dank. die Verkettung der awaits kam mit heute Mittag auch bei einem Spaziergang mit dem Hund im Wald. Manchmal soll man mit Anstand auf die Dinge schauen. Für die Nachwelt halte ich nochmal den gesamten Code fest, wie es funktioniert: Am Ende der geladenen Seite rufe ich initCanvas() auf. Diese asynchrone Funktion übernimmt dann den kompletten Aufbau. drawCanvas() komt dann zum Schluß Wichtig ist, daß alles in dieser async Funktion steht, denn nur so wird es nacheinander abgearbeitet. Nimmt der Benutzer Änderungen an den darzustellenden Objekten vor muß genauso verfahren werden. In einer async Funktion nacheinander die hinzugekommenen Bilder laden und die Objekte dazu anlegen. Eigentlich ganz einfach, wenn man weiß wie es geht Code: function loadImage (path) |