Samuel fiedler: Coding Roboter alle Schritte voneinander trennen

Hallo alle!

Ich habe einen kleinen Coding-Roboter gebaut. Soweit funktioniert alles schon gut, außer die Responsivität (der Hintergrund ist auf kleinen Screens einfach zu groß).

Der Coding-Roboter funktioniert recht einfach. Bisher hat er nur drei Befehle: nachVorne(), dreheLinks() und dreheRechts().
Ich habe das alles schön in einem Fiddle online gestellt.

Jetzt aber zu der eigentlichen Frage:
Wie kann ich die Schritte voneinander durch Zeit trennen?
Ich habe das Problem zu lösen versucht, indem ich in jede Funktion asynchron gemacht habe und dann await delay(1) geschrieben habe, wobei die delay-Funktion so aussieht:

function delay(n) {
  return new Promise(function (resolve) {
    setTimeout(resolve, n * 1000);
  });
}

Das Problem dabei ist, dass der Automat einmal ca. eine Sekunde wartet und dann alle Schritte hintereinander ausführt.

Ich freue mich auf Anregungen!

Bonjour,
Samuel Fiedler

akzeptierte Antworten

  1. Hallo Samuel,

    das Problem ist, dass eine async-Funktion mit einem Promise zurückkehrt, sobald der Code auf einen await stößt. Code, der erst laufen soll, wenn alle asnychronen Teile der Funktion ausgeführt sind, muss im then-Teil dieses Promise laufen.

    async/await kapseln Promises lediglich. D.h. wenn ich dies tue:

    nachVorne();
    nachVorne();
    nachVorne();
    

    dann kehrt der erste Aufruf fast sofort zurück und sein Delay läuft im Hintergrund ab. D.h. der zweite Aufruf erfolgt fast sofort nach dem ersten, der dritte gleich hinterher. Die setTimeout-Verzögerungen aller Aufrufe überlappen sich zum größten Teil, und dann rendern sie wieder direkt nacheinander.

    Wenn Du willst, dass ein nachVorne Aufruf auf den vorigen wartet, muss das mit Promises so aussehen:

    nachVorne()
    .then(() => nachVorne())
    .then(() => nachVorne());
    

    Await ist Syntaxzucker dafür, dies hier tut im Wesentlichen das Gleiche:

    await nachVorne();
    await nachVorne();
    nachVorne();
    

    Das fliegt Dir aber um die Ohren, weil await nur in einer async-Funktion erlaubt ist. Ein eval-Kontext ist keine async-Funktion. Du müsstest im Code-Feld beispielsweise schreiben:

    async function run() 
    {
    await nachVorne();
    await nachVorne();
    await nachVorne();
    await nachVorne();
    }
    
    run();
    

    Dann geht es, weil er nun nach jedem Schritt wirklich wartet.

    Man kann es auch mit einer Immediately Invoked Function Expression (IIFE) machen:

    (async function() {
      await nachVorne();
      await nachVorne();
      await nachVorne();
      await nachVorne();
    })()
    

    und jetzt wird's interessanter, denn die awaits kann man durch search&replace in den Textarea-Inhalt hineinzaubern und die beiden Zeilen, die den IIFE-Rahmen bilden, noch drumherumbauen.

    Deine start-Funktion könnte so aussehen:

    function start() {
      let text = document.getElementById('code')
                         .value
                         .replace(/nachVorne|dreheLinks|dreheRechts/g,
                                  m => "await " + m);
      eval("(async function() {" + text + "})()");
    }
    

    Und damit kannst Du in dein Codefeld auch dies schreiben:

    for (i=0; i<10; i++) {
     nachVorne();
     dreheLinks();
    }
    

    Das wird automatisch konvertiert zu

    (async function() {for (i=0; i<10; i++) {
     await nachVorne();
     await dreheLinks();
    }})()
    

    und schön schrittweise ausgeführt.

    Lediglich die Drehung des Kopfes von 270 auf 0 ist noch ätzend. Er dreht nicht um 90°, sondern um 270° in die Gegenrichtung. Viel Spaß damit.

    Rolf

    --
    sumpsi - posui - obstruxi