Exploring Asynchronous JavaScript

OP #7589425
Lesenswert?

Ich bin dabei, mich auf eine schwierige Reise durch die Welt des asynchronen JavaScript zu begeben, und suche demütig den Rat und die Erfahrung unserer angesehenen JavaScript-Enthusiasten. Bei der vorliegenden Arbeit geht es darum, die Komplexität der asynchronen Programmierung in JavaScript aufzudecken, ein Bereich, der mir bei der Suche nach Wissen enorme Hürden bereitet hat.

1
// This code snippet delves into the world of Asynchronous JavaScript
2
function fetchData(url) {
3
    // Asynchronous code for fetching data from the provided URL
4
}
5

6
// Example usage of the fetchData function
7
fetchData('https://api.example.com/data')
8
    .then(data => {
9
        // Handle the retrieved data asynchronously
10
    })
11
    .catch(error => {
12
        // Handle errors that occur during the asynchronous operation
13
    });

Es ist wichtig zu betonen, dass meine Suche über ein oberflächliches Verständnis hinausgeht. Vielmehr motiviert mich der echte Wunsch, die Komplexität der asynchronen Programmierung in JavaScript zu verstehen. Daher wünsche ich mir dringend Ihren hervorragenden Rat und Ihre Ideen für die Bewältigung dieses komplexen Themas. Angesichts der Schwere dieser Arbeit benötige ich dringend Ihre Hilfe bei der Identifizierung häufiger Probleme und Missverständnisse über asynchrones JavaScript. Darüber hinaus würde ich mich über Ideen, Best Practices oder Ansätze freuen, die mir helfen könnten, diesen Bereich besser zu verstehen. Quelle: https://www.scaler.com/topics/course/javascript-beginners/

#7589471
Lesenswert?

Hat es die verlinkte Seite tatsächlich nötig, dass man sie auf diese plumpe Weise bewirbt?

Oder ist dir bewusst, dass du ihr mit solch nervigem Gespamme in Foren eher schadest, und du machst das, weil du den Betreiber nicht magst?

Oder hast du tatsächlich eine konkrete Frage, und nur vergessen, sie hinzuschreiben?

#7589475
Lesenswert?

Kontrollier mal, ob dieser Kurs nicht massiv veraltet ist...

"fetchData" selber zu schreiben ist unnötig, gibt ja "fetch" fix und fertig im Browser. https://caniuse.com/fetch

Asynchrone Funktionen sollte man als "async function" schreiben. Oder ein Promise returnen. https://caniuse.com/async-functions

ein

const reply = await fetch("https://....");

ist viel einfacher zu lesen als diese verschachtelte Callback/then-chain-Hölle, die vor 5-10 Jahren noch üblich war.

#7589928
Lesenswert?

Befor es in JS "Promise" gab hat man Callback Funktionen genutzt. Also man übergab einer Funktion eine Callback Funktion, die am Ende aufgerufen wurde, normalerweise mit dem Resultat oder einem Fehler.

Dann kamen die Promise Objekte. Das ist eine gute Abstraktion davon, die das konsistenter macht. Dort kann man mit then() die Callback Funktion übergeben. Man hat 2, eine für Fehler, und eine für wenn alles OK ist. Die Promise kann das Resultat speichern, und es kennt die Zustände ausstehend, fertig, oder Fehler.

Bei "new Promise" kann man eine Funktion übergeben, die sofort aufgerufen wird, und wenn sie fertig ist, den an sie übergebenen Callback aufruft, der dann den Wert der Promise setzt. Das ist eigentlich wie früher mit den Callbacks. Man kann zwischen den 2 Varianten, Callback übergeben und Promise zurück geben, Konvertieren, in nodejs gibt es dafür fertige Funktionen "util.promisify" und "util.callbackify". In dem sinne ist das äquivalent.

So ein Promise Objekt hat aber noch einige Vorteile. Man kann z.B. auf mehrere Ergebnisse auf einmal warten, und weil man beim Callback, das man an then() übergibt, ein Promise Objekt übergeben kann, kommt man ohne tief verschachtelte Callbacks aus. Und bei den Callbacks die man der then() Funktion übergibt, hat man das Problem nicht, dass man einen Fehler haben könnte, und vergisst, den Abzufangen und den reject Callback aufzurufen, dass kann die then() funktion auch.

Hier gibt es nun noch etwas spezielles, bei den Promise Objekten. In JS gibt es das Konzept eines Objekts, dass then-able ist. Das ist jedes Objekt, dass eine then funktion hat, der ein Callback übergeben wird, der dann aufgerufen wird. Das ist unter anderem für nicht native Promise Implementierungen wichtig, was bei der Einführung wichtig war. Eine Promise ist ein then-able Objekt, und then-able Objekte werden wie Promises behandelt. Man kann also z.B. sowas machen:

1
Promise.resolve({then(resolve){ setTimeout(resolve, 1000); }})
2
       .then(()=>{console.log("I was called 1 second later");});

Das ganze war manchmal aber immer noch fehleranfällig, und nicht ganz so praktisch wie möglich. z.B. hatte man bei "new Promise" immer noch callbacks, die man vergessen könnte, aufzurufen (und die Variante mit den then-ablen Objekten von oben kannten die wenigsten). Deshalb wurden async Functionen, und das await Keyword eingeführt.

Eine async Funktion gibt eine Promise zurück. Und immer eine Native, man kann die nicht ersetzen*. Gibt es eine Exception, wird die Promise immer rejected, da kann man (fast) nichts falsch machen. Und nur in den async Funktionen, gibt es das await keyword. Laut spec wartet man damit auf Promises. Tatsächlich wird aber einfach die then() Funktion aufgerufen, und dieser eine Continuation der then() Funktion übergeben.

1
(async()=>{
2
  await { then(continuation){ setTimeout(continuation, 1000); } };
3
  console.log("I was called 1 second later");
4
})();

Die Continuation ist wie eine simple callback Funktion, die die Async funktion fortsetzt. Sie wird aber niemals synchron aufgerufen:

1
(async()=>{
2
  console.log(1);
3
  console.log(await {
4
    then(continuation){
5
      console.log(2);
6
      continuation("result");
7
      console.log(3);
8
    }
9
  });
10
  console.log(4);
11
})();

Ausgabe:

1
1
2
2
3
3
4
result
5
4

Wie hier zu sehen ist, wird continuation nicht sofort ausgeführt, sondern erst beim nächsten event loop Durchgang.

Letztendlich kommt es aber aufs gleiche raus. Man kann auf eine Promise Warten.
Das heisst aber auch, dass bei jedem Await, eine Funktion unterbrochen, und andere Funktionen im event loop aufgerufen werden können. Aber nur dort, die restlichen teile der Funktion werden niemals unterbrochen.
Ein paar Fallstricke hat das auch, aber es ist viel einfacher damit umzugehen als beim Multithreading, und manchmal kann man das sogar anderweitig ausnutzen.

Zu guter letzt, der Vollständigkeit halber, sind noch Generator Funktionen zu erwähnen. Die gab es schon lange vor Promise Objekten und vor async-await. Dort werden die Funktionen beim "yield" Keyword unterbrochen, und das beim Aufruf des Generators zurückgegebene Objekt hat eine next() Funktion, quasi aine continuation, das führt die Funktion fort, und man kann das yield so sogar werte zurückgeben lassen.

1
function* mygenerator(){
2
  console.log(1);
3
  console.log(yield 2);
4
  console.log(yield 3);
5
}
6
var x = mygenerator();
7
console.log(0);
8
console.log(x.next("a"));
9
console.log(x.next("b"));
10
console.log(x.next("c"));

Ausgabe:

1
0
2
1
3
{ value: 2, done: false }
4
b
5
{ value: 3, done: false }
6
c
7
{ value: undefined, done: true }

In gewissem Sinne ist das analog zu async Funktionen, man könnte die damit simulieren, das wäre aber weder Sinvoll noch Praktisch. Sind dafür für anderes gut. So ein Generator kann man auch mit for(x of g) nutzen. Und das lässt sich auch mit async kombinieren, nennt sich dann async generatoren. Die kann man mit "for await(x of ag)" iterieren.

Da gäbe es noch viel mehr zu sagen, aber das dürfte alles wichtige zusammenfassen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren