Zum Inhalt springen

Aufgabe 03-1a - Reihenfolge-Rätsel

Zu Zen-Modus wechseln
  • Du erklärst das Ausführungsmodell von JavaScript (Call Stack, Event Loop, Microtask- und Task-Queue) an einer eigenen Skizze.
  • Du sagst die Ausgabereihenfolge von Code mit Timern, Promises und await voraus und prüfst die Vorhersage am Rechner.
  • Du begründest jede Abweichung mit dem Modell statt mit Bauchgefühl und erkennst dabei das vergessene await an seiner Ausgabe.
  • Du konstruierst eigene Rätsel, die eine typische Fehlvorstellung aufdecken und trotzdem fair erklärbar sind.

Ein guter Kellner weiß in jedem Moment, welcher Teller als Nächstes aus der Küche kommt. Genau diese Fähigkeit trainierst du hier, nur mit Codezeilen statt Schnitzeln.

Wer den Event Loop verstanden hat, kann asynchronen Code vorhersagen. Du bestimmst die Ausgabereihenfolge vorbereiteter Codeschnipsel, prüfst deine Vorhersagen am Rechner und erklärst jede Abweichung mit dem Modell (siehe Kapitel Asynchrones JavaScript, Einheit 3.1 für die Stufe Wesentlich_überwiegend, Einheit 3.2 ab Wesentlich_vollständig). Die Übung ist bewusst eine Denk- statt Tippübung: Der Event Loop entscheidet über jedes Async-Verhalten des restlichen Jahres.

Das Rätselblatt puzzles.js enthält acht Codeschnipsel als Funktionen puzzle1() bis puzzle8(); ein Runner am Dateiende führt alle nacheinander aus. Du brauchst Node.js und Papier und Kugelschreiber für Vorhersagen und Skizze.

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.
  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.
  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe
  • Die Übung liegt als Unterordner uebung-03-1a in deinem Jahres-Repository SJ26_27_4AHITM_SEW_<Benutzername>_exercises. Darin liegen puzzles.js, eine Datei raetselblatt.md mit Vorhersagen, tatsächlichen Ausgaben und Erklärungen sowie ein Foto oder Scan deiner Modellskizze. Du arbeitest allein.
  • Kugelschreiber-Ehrlichkeit: Du notierst jede Vorhersage, bevor du ausführst, und änderst sie danach nicht mehr. Bewertet wird nicht die Trefferquote, sondern die Qualität deiner Erklärungen.
  • Sag die Ausgabe dieses Codes voraus, prüf sie danach und erklär in zwei Sätzen mit den Begriffen Call Stack und Task-Queue, warum two zuletzt kommt, obwohl der Timer auf 0 steht:

    console.log("one");
    setTimeout(() => console.log("two"), 0);
    console.log("three");
  • Löse die Rätsel 1, 2, 4 und 5 aus puzzles.js: erst die Reihenfolge notieren, dann ausführen, die tatsächliche Ausgabe daneben schreiben. Bei jeder Abweichung: ein bis zwei Sätze, was du übersehen hast.

  • Zeichne das Event-Loop-Modell als Skizze: Call Stack, Laufzeitumgebung mit Timern, Microtask-Queue, Task-Queue und den Loop.

  • Erklär an deiner Skizze Rätsel 5 Schritt für Schritt schriftlich: Was liegt wann wo?

Tipp: Frag bei jeder Zeile: Läuft sie jetzt (synchron)? Kommt sie in die Microtask-Queue (then)? Oder in die Task-Queue (setTimeout)? Ein einzelnes Rätsel führst du aus, indem du im Runner am Dateiende die anderen auskommentierst oder in der Node-REPL nur puzzle5() aufrufst.

Vollständig, wenn:

  • zum Aufwärm-Code und zu den Rätseln 1, 2, 4 und 5 je eine unveränderte Vorhersage und die tatsächliche Ausgabe vorliegen.
  • jede Abweichung mit dem Modell erklärt ist (Call Stack, Microtask-Queue, Task-Queue), nicht mit “war halt so”.
  • die Skizze beide Warteschlangen enthält und die Erklärung von Rätsel 5 vollständig und korrekt ist.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Löse die Rätsel 3, 6, 7 und 8 genauso: Vorhersage, Ausgabe, Erklärung jeder Abweichung.
  • Erklär Rätsel 8 an deiner Skizze Schritt für Schritt schriftlich.
  • Formuliere den Merksatz “Asynchron heißt später, nie zwischendurch” und die Folgerung daraus, dass Blockieren alles blockiert, in eigenen Worten.

Tipp: Eine async-Funktion läuft synchron bis zum ersten await; erst der Rest danach wird zur Microtask, auch bei await null. Bevor du eine geloggte Variable vorhersagst, frag dich, ob dort schon der fertige Wert liegt oder noch etwas anderes (Einheit 3.2, Abschnitt “Das vergessene await”). Rätsel 8 ist das schwerste: Zeichne beide Warteschlangen auf Papier und streich ab, was ausgeführt wurde.

Vollständig, wenn:

  • zu den Rätseln 3, 6, 7 und 8 je eine unveränderte Vorhersage, die tatsächliche Ausgabe und bei Abweichungen eine Erklärung mit dem Modell vorliegen.
  • die Schritt-für-Schritt-Erklärung von Rätsel 8 vollständig und korrekt ist.
  • Merksatz und Folgerung in eigenen Worten und sachlich richtig formuliert sind.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Ordne in einer Tabelle jedem der acht Rätsel den Mechanismus zu, den es prüft (zum Beispiel “Microtask vor Task”, “async läuft synchron bis zum ersten await”), und begründe die Zuordnung in je einem Satz.
  • Bau ein Rätsel, bei dem eine innerhalb eines then neu erzeugte Microtask noch vor einem längst wartenden setTimeout(..., 0) läuft. Führ es aus und erklär in zwei Sätzen, warum.

Tipp: Manche Rätsel prüfen mehr als einen Mechanismus. Für das eigene Rätsel genügen drei bis fünf Zeilen.

Vollständig, wenn:

  • die Tabelle alle acht Rätsel enthält und die Zuordnungen stichhaltig begründet sind.
  • das eigene Rätsel ausgeführt ist, die notierte Ausgabe stimmt und die Erklärung nennt, dass die Microtask-Queue vollständig geleert wird, bevor ein Task drankommt.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Konstruiere zwei eigene Rätsel: eines, das ein typisches Missverständnis ausnutzt (Kandidaten: await in einer Schleife, vergessenes await, then gemischt mit await), und eines, dessen Ausgabe auf den ersten Blick unmöglich wirkt, aber fair erklärbar ist.
  • Schreib zu jedem Rätsel die Lösung: erwartete Ausgabe plus Erklärung am Modell. Führ das Rätsel aus und prüf, dass deine Lösung stimmt.
  • Tausch deine Rätsel mit einer Kollegin oder einem Kollegen und löst gegenseitig. Beurteilt schriftlich: Täuscht das Rätsel? Ist es fair erklärbar? Ein gutes Rätsel erfüllt beides.

Tipp: Rätsel, die auf echten, unterschiedlich langen Wartezeiten oder Zufall beruhen, sind nicht fair erklärbar. Bleib bei setTimeout(..., 0), then und await.

Vollständig, wenn:

  • beide Rätsel ausgeführt sind und die Lösung mit der tatsächlichen Ausgabe übereinstimmt.
  • die Rätsel täuschen und fair erklärbar sind.
  • die Beurteilung der getauschten Rätsel konkret benennt, was täuscht und ob die Lösung stimmt.

Wie unter Allgemein.

  1. Wann arbeitet der Event Loop die Warteschlangen ab, und welche kommt zuerst dran?
  2. Warum kann laufender synchroner Code nie von einem Callback unterbrochen werden?
  3. Was passiert mit wartenden Callbacks, während eine Endlosschleife läuft?
  4. Ein async-Aufruf ohne await: Was landet in der Variablen?
  5. Warum ist “Timer auf 0” keine Garantie für “sofort”?

Durchschnittlich bis Wesentlich_vollständig: ca. 100 min

  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules