Dani: async await

Halli Hallo,

ich lerne gerade async await im Unterschied zu Promises, mit denen ich mich glaub ich auskenne.

Jetzt wollte ich eine Funktion auf reine async await Syntax umschreiben, das ist mein Ausgangscode

const waitForThis = async() => {
  return new Promise(resolve => {
	setTimeout(() => {resolve()}, 1000);
  });

};

(async function() {
  console.log("vorher");
  await waitForThis();
  console.log("nachher");
}());

Ich wollte nur übungshalber also das letzte "Promise" loswerden, aber das geht hier eigentlich nicht, oder? Weil

await setTimeout(() => {resolve()}, 1000);

gibt ja nichts zurück, daher wartet console.log("nachher") nicht, oder?

Geht das hier gar nicht ohne new Promise? Oder verstehe ich async await noch immer nicht ganz 🤔

Danke! Liebe Grüße, Dani

  1. Sorry sorry sorry

    statt

    await setTimeout(() => {resolve()}, 1000);
    

    meinte ich

    await setTimeout(() => {/* Irgendeine Funktion */}, 1000);
    
  2. Tach!

    ich lerne gerade async await im Unterschied zu Promises, mit denen ich mich glaub ich auskenne.

    async-await ist kein Gegenstück zu Promises sondern nur eine Eweiterung für Promise-Verwender, so dass die Promise-Chain wegfällt. Der Promise-Ersteller muss hingegen weiterhin Promise-Objekte verwenden.

    Geht das hier gar nicht ohne new Promise? Oder verstehe ich async await noch immer nicht ganz 🤔

    Man kann nur Promises "await"en, also kann man Promises nicht mit async-await loswerden.

    dedlfix.

    1. Hallo dedlfix,

      Der Promise-Ersteller muss hingegen weiterhin Promise-Objekte verwenden.

      Nein. Jede async-Funktion gibt automatisch ein Promise zurück, das durch den return der async-Funktion resolved wird.

      Heißt aber auch: Alles, was hinter await steht, wird in die Mikrotask-Queue verschoben. Egal, ob in der async-Funktion etwas asynchrones passiert oder nicht.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Tach!

        Der Promise-Ersteller muss hingegen weiterhin Promise-Objekte verwenden.

        Nein. Jede async-Funktion gibt automatisch ein Promise zurück, das durch den return der async-Funktion resolved wird.

        Ja, stimmt schon, Promises oder Thenables oder anderes. Aber nur mit Promises/Thenables ist man in der Lage, ein asynchrones Ergebnis zu liefern, sonst bleibt man quasi-synchron.

        dedlfix.

  3. Hallo Dani,

    async und await sind ein Sprachkonstrukt, das eine Verkleidung der Promises darstellt. Auch „Syntaxzucker“ genannt.

    Das heißt:

    • Du kannst jede Funktion awaiten, die ein Promise zurückliefert.
    • Jede Funktion, die async ist, gibt ein Promise zurück, d.h. Du kannst auf ihrem Ergebnis .then und .catch aufrufen

    Da es kein Promise-basierendes Systemkonstrukt gibt, das eine Zeitverzögerung erzeugt, bist Du bei setTimeout auf ein manuelles Promise angewiesen. Dafür bietet sich ein Konstrukt ohne explizites async an:

    (Edit: Dedlfix' Hinweise eingearbeitet)

    function delay(milliseconds, data) {
      return new Promise((resolve, reject) => setTimeout(resolve, milliseconds, data));
    }
    
    delay(1000, "hugo")
    .then(h => console.log(h));
    
    // ODER
    
    let h = await delay(1000, "hugo");
    console.log(h); 
    

    gibt in beiden Fällen 1s "hugo" aus.

    Der zweite Parameter für <code>delay</code> greift als Rest-Parameter (erkennbar am ...) alle Parameter hinter dem Timeout auf und übergibt sie per Spread-Operator (das ...) als einzelne Parameter ab Position 3 an setTimeout. Von setTimeout werden diese Parameter dann Timeout-Handler durchlauferhitzt, d.h. die Parameter 2 bis N von delay landen als Parameter 3 bis (N+1) bei setTimeout und dann als Parameter 1 bis (N-1) im then-Handler.

    ... - je nach Kontext Rest oder Spread. Confused? Me too 😉

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Tach!

      • Du kannst jede Funktion awaiten, die ein Promise zurückliefert.

      Es muss nicht einmal ein vollständiges Promise sein. Es recht, wenn das zurückgegebene Objekt "thenable" ist, also eine Funktion namens then enthält.

      Man kann übrigens auch andere Dinge als Promises/Thenables awaiten, aber dann wird der Wert in ein erfülltes Promise gewandelt und zurückgegeben. Damit sieht es so aus, als sei auch setTimeout() awaitable, weil das anstandslos durchgeht. Das Ergebnis ist dann nicht anders als ohne await.

      function delay(milliseconds, ...data) {
        return new Promise((resolve, reject) => setTimeout(resolve, delay, ...data));
      };
      

      Wenn du das reject nicht brauchst, kannst du es weglassen. Und das delay im setTimeout()-Aufruf sollte sicher ein milliseconds sein.

      Außerdem nimmt resolve nur ein einzelnes Argument an, das Spreading ist also nicht zielführend. Ein Parameter wird durchgereicht, der Rest geht verloren.

      Aber wenn das Ziel ist, das delay zu awaiten, dann muss ich da nicht noch Daten durchschleifen, denn die habe ich ja bereits im aktuellen Kontext zur Verfügung, und sie werden weder durch das setTimeout noch durch das Promise geändert.

      Und das Semikolon nach der Funktionsdefinition ist überflüssig.

      function delay(milliseconds) {
        return new Promise(resolve => setTimeout(resolve, milliseconds));
      }
      
      const hugo = 'hugo';
      delay(1000)
        .then(() => console.log(hugo));
      
      // ODER
      
      const hugo = 'hugo';
      await delay(1000);
      console.log(hugo); 
      

      dedlfix.

      1. Hallo dedlfix,

        das kommt davon, wenn man hin und her editiert. Der Parameter hieß mal delay, aber in einer Funktion namens delay hätte das einen Namenskonflikt geben können. Okay, tut's nicht, hatte keine Lust zum Probieren.

        Dass then nur einen Parameter hat, hatte ich übersehen. Stimmt natürlich.

        Die Signatur des new Promise-Callback behalte ich aber bei. Man kann den zweiten Parameter weglassen, sicher, aber er gehört zum Promise-Protokoll dazu und darum lasse ich ihn stehen.

        Aber wenn das Ziel ist, das delay zu awaiten, dann muss ich da nicht noch Daten durchschleifen

        Kommt darauf an. Wenn der then gleich nach dem delay-Aufruf steht, ist das so. Aber das delay-Promise könnte ja auch weitergereicht werden, und setTimeout bietet das Feature auch an. Ein "universelles" Delay-Promise sollte das also können.

        Rolf

        --
        sumpsi - posui - obstruxi