Wie Microtasks / Macrotasks dressieren?
Christian Schubert
- javascript
Hallo,
Je umfangreicher ein Programm wird, desto unübersichtlicher wird es mitunter leider auch, daher suche ich nach einer zuverlässigen Methode, wie ich Funktionen so aufrufen kann, dass eine nach der anderen konsequent chronologisch abgearbeitet wird.
"Problem" hierbei ist natürlich (bei näherer Betrachtung macht das ja auch Sinn), dass Javascript nicht Funktion um Funktion abarbeitet, sondern eben alle Microtasks in der Queue, bevor der nächste Macrotask angegangen wird.
...ergo ist die Strategie, Funktionen einfach chronologisch aufzurufen, dann um Scheitern verurteilt, wenn verschiedene Funktionen verschiedene Micro- wie auch Macrotasks beinhalten.
Dafür gibt es jetzt eine Handvoll Strategien, bin allerdings ein wenig unschlüssig, was da wohl die beste Herangehensweise ist.
Jede Funktion mit einem Timeout? (PUH…) MutationObservers? EventListeners transitionend/animationend?
Wie würdet ihr das angehen?
Quasi ein Workaround für etwas in der Art wie
/* Achtung DummyCode */ Function.addEventListener('callstackEmpty', nextFunction);
Danke für eure Gedanken!
Tach!
Es kann sein, dass ich dein Problem nicht verstehe, aber ...
...ergo ist die Strategie, Funktionen einfach chronologisch aufzurufen, dann um Scheitern verurteilt, wenn verschiedene Funktionen verschiedene Micro- wie auch Macrotasks beinhalten.
... Macrotasks werden meines Wissens mit setTimeout()/setInterval() gestartet, sollen also gar nicht im Fluss, sondern zu einem späteren Zeitpunkt laufen. Auch Events sind Macrotasks, die zufällig auftreten und sich in die Task Queue einreihen, und eigentlich nicht in einer bestimmten Reihenfolge mit Microtasks anderer Macrotasks synchronisiert werden müssen. Bleibt noch, die Microtasks zu organisieren.
Dafür gibt es jetzt eine Handvoll Strategien, bin allerdings ein wenig unschlüssig, was da wohl die beste Herangehensweise ist.
Was spricht gegen Promises beziehungsweise async/await?
Wie würdet ihr das angehen?
Kommt darauf an, was ich für ein Problem zu lösen versuche. Vielleicht muss auch RxJS her, wenn Promises nicht zielführend sind.
dedlfix.
Hallo Christian,
die Queues kommen nur dann ins Spiel, wenn Du auch was reinstellst. Normale Funktionsaufrufe werden da ausgeführt, wo sie im Code stehen.
Wenn Du einen HAUFEN Ereignisquellen hast, die alle kreuz und quer mit Promises und setTimeout Einträge in Mikro- und Makrotaskqueue machen, dann wird es natürlich schwierig.
Die Frage ist ja, was Du eigentlich tust. Wenn man seinen Code halbwegs beieinander hat, dann bearbeitet ein Codeteil auch nur ein Stück der Daten, und andere Codeteile andere Daten. Was diese beiden Teile tun, ist unabhängig voneinander und braucht keine definierte Verarbeitungsreihenfolge. Wenn Du mehrere asynchrone Stränge hast, und irgendwann an einen Punkt kommst, wo beide Stränge fertig sein müssen, dann brauchst Du Synchronisierungsobjekte. Das kann z.B. ein durch Promise.all() erzeugtes Sammelpromise sein. Da läuft der then-Handler los, wenn alle an der Erzeugung beteiligten Promises resolved sind.
Was ich sagen will: synchronisiere nur, was Du auch synchronisieren musst. Du musst es dann, wenn Datenabhängigkeiten bestehen. Und die sollten sich durch Callbacks oder Promises abbilden lassen.
Rolf
Hallo,
danke für eure Gedanken! :)
Promises sind nur leider Microtasks i.e. werden vor dem nächsten Macrotask (auch vor solchen, die in chronologisch eigentlich vorangehenden Funktionen definiert sind!) ausgeführt.
Tach!
Promises sind nur leider Microtasks i.e. werden vor dem nächsten Macrotask (auch vor solchen, die in chronologisch eigentlich vorangehenden Funktionen definiert sind!) ausgeführt.
Ich denke, es ist für unser Verständnis notwendig, dass du ein Beispiel dessen zeigst, was dein Problem ist. Konkret wäre da die Frage, wie du deine Macrotasks erzeugst.
dedlfix.
Hallo,
der Code macht eigentlich keine Probleme [und trägt wohl auch zum besseren Verständnis relativ wenig bei], die Frage ist eher eine grundsätzlichere.
Prinzipiell funktioniert alles, wie es soll. Du hast aber Recht - es bringt wohl nicht viel, lange um des Kaisers Bart herumzureden und euch so unnötig die Zeit zu stehlen, daher, um konkret zu werden:
in einem Fall ist es zum Beispiel so, dass Positionseigenschaften (top, left, ...) von Elementen im DOM verändert werden (erste Funktion), dann einige Berechnungen passieren und die Positionseigenschaften abermals verändert werden (zweite Funktion) - dieses Mal animiert.
Da es sich beim Repaint des DOM um Macrotasks handelt, werden sowohl die Positionsveränderungen der ersten, als auch der zweiten Funktion hintangestellt, was natürlich unerwünschte Nebenwirkungen mit sich bringt (nochmal, mir ist auch vollkommen bewusst, warum ich das Resultat erziele, das ich erziele):
erzieltes Resultat:
BERECHNUNGEN > DOM REPAINT > DOM REPAINT
👎
gewünschtes Resultat:
DOM REPAINT > BERECHNUNGEN > DOM REPAINT
👍
Hallo Christian,
animiert
Das ist ein Schlüsselwort für requestAnimationFrame. Im Callback dazu führst Du die erforderlichen Berechnungen und DOM Updates aus.
Wenn es nur genau zwei Repaints gibt, kannst Du es auch mit setTimeout machen. Aber requestAnimationFrame ist besser an das Monitor-Timing angepasst.
Ist es dagegen ein Spiel, oder eine länger laufende Animationssequenz aus mehreren Schritten, die Stück für Stück berechnet werden? Dann in jedem Fall requestAnimationFrame.
Kontrollfrage: Die Animation ist so, dass Du sie mit CSS Mitteln nicht ausführen kannst?
Rolf
Hallo Rolf,
Die Animationen laufen (wo möglich) natürlich über CSS-Klassen, die Fäden dafür werden via Javascript gezogen 😃
Mittlerweile bin ich aber mit einem grundlegenden CleanUp meines Codes beschäftigt und daher im Prozess, die Gesamtstrategie prinzipiell neu zu überdenken.
...daher ist es (denke ich) fürs Erste wohl müßig, hier weiter zu philosophieren und euch mit vielleicht unnötigen Fleißaufgaben Zeit und Nerven zu rauben (wie gesagt, ich muss jetzt mal grundlegend evaluieren, was ich da eigentlich wie genau verbrechen möchte).
Melde mich aber, sollte ich wieder anstehen, danke für eure Hilfestellungen!
LG, Christian.
Hallo Christian,
mach das. Und wenn's geht, zeig den Code gerne vor. Dann diskutiert und zankt es sich besser 😂
Rolf