Asynchrone Programmierung ist ein Programmierparadigma, das es Ihnen ermöglicht, Code zu schreiben, der asynchron ausgeführt wird. Im Gegensatz zur synchronen Programmierung, die Code sequenziell ausführt, erlaubt die asynchrone Programmierung, dass Code im Hintergrund läuft, während der Rest des Programms weiterhin ausgeführt wird. Dies ist besonders nützlich für Aufgaben, die lange dauern können, wie das Abrufen von Daten von einer entfernten API.

Asynchrone Programmierung ist entscheidend für die Erstellung reaktionsfähiger und effizienter Anwendungen in JavaScript. TypeScript, ein Superset von JavaScript, erleichtert die Arbeit mit asynchroner Programmierung noch weiter.

Es gibt mehrere Ansätze zur asynchronen Programmierung in TypeScript, einschließlich der Verwendung von Promises, async/await und Callbacks. Wir werden jeden dieser Ansätze im Detail behandeln, damit Sie die besten für Ihren Anwendungsfall auswählen können.

Inhaltsverzeichnis

  1. Warum ist asynchrone Programmierung wichtig?

  2. Wie TypeScript die asynchrone Programmierung erleichtert

  3. Wie man Promises in TypeScript verwendet

  4. Wie man Async / Await in TypeScript verwendet

  5. Wie man Callbacks in TypeScript verwendet

  6. Fazit

Warum ist asynchrone Programmierung wichtig?

Asynchrone Programmierung ist entscheidend für den Aufbau reaktionsfähiger und effizienter Webanwendungen. Sie ermöglicht es, Aufgaben im Hintergrund auszuführen, während der Rest des Programms fortgesetzt wird, wodurch die Benutzeroberfläche auf Eingaben reagiert bleibt. Außerdem kann asynchrone Programmierung die Gesamtleistung steigern, indem mehrere Aufgaben gleichzeitig ausgeführt werden können.

Es gibt viele Beispiele aus der realen Welt für asynchrone Programmierung, wie den Zugriff auf Benutzerkameras und -mikrofone sowie die Verarbeitung von Benutzereingaben. Selbst wenn Sie nicht häufig asynchrone Funktionen erstellen, ist es wichtig zu wissen, wie man sie korrekt verwendet, um sicherzustellen, dass Ihre Anwendung zuverlässig ist und gut funktioniert.

Wie TypeScript die asynchrone Programmierung erleichtert

TypeScript bietet mehrere Funktionen, die die asynchrone Programmierung vereinfachen, darunter Typsicherheit, Typinferenz, Typüberprüfung und Typannotationen.

Mit der Typsicherheit können Sie sicherstellen, dass Ihr Code wie erwartet funktioniert, selbst bei der Arbeit mit asynchronen Funktionen. Zum Beispiel kann TypeScript Fehler im Zusammenhang mit null- und undefined-Werten bereits zur Kompilierzeit erkennen und Ihnen so Zeit und Aufwand bei der Fehlersuche ersparen.

Die Typinferenz und -überprüfung von TypeScript reduzieren auch die Menge an Standardcode, den Sie schreiben müssen, was Ihren Code prägnanter und leichter lesbar macht.

Und die Typannotationen von TypeScript sorgen für Klarheit und Dokumentation Ihres Codes, was besonders hilfreich ist, wenn Sie mit asynchronen Funktionen arbeiten, die komplex zu verstehen sein können.

Lassen Sie uns nun eintauchen und mehr über diese drei Schlüsselfunktionen der asynchronen Programmierung erfahren: Versprechen, async/await und Rückrufe.

Verwendung von Versprechen in TypeScript

Versprechen sind ein leistungsstolles Werkzeug zum Umgang mit asynchronen Operationen in TypeScript. Beispielsweise könnten Sie ein Versprechen verwenden, um Daten von einer externen API abzurufen oder eine zeitaufwändige Aufgabe im Hintergrund auszuführen, während Ihr Hauptthread weiterläuft.

Um ein Versprechen zu verwenden, erstellen Sie eine neue Instanz der Promise-Klasse und übergeben ihr eine Funktion, die die asynchrone Operation durchführt. Diese Funktion sollte die resolve-Methode mit dem Ergebnis aufrufen, wenn die Operation erfolgreich ist, oder die reject-Methode mit einem Fehler, wenn sie fehlschlägt.

Nachdem das Versprechen erstellt wurde, können Sie Rückrufe daran anhängen, indem Sie die then-Methode verwenden. Diese Rückrufe werden ausgelöst, wenn das Versprechen erfüllt ist, und der aufgelöste Wert wird als Parameter übergeben. Wenn das Versprechen abgelehnt wird, können Sie einen Fehlerbehandler mit der catch-Methode anhängen, der mit dem Grund für die Ablehnung aufgerufen wird.

Die Verwendung von Versprechen bietet mehrere Vorteile gegenüber traditionellen rückrufbasierten Methoden. Zum Beispiel können Versprechen helfen, „Callback-Hölle“ zu vermeiden, ein häufiges Problem in asynchronem Code, bei dem verschachtelte Rückrufe schwer zu lesen und zu pflegen sind.

Versprechen erleichtern auch die Fehlerbehandlung in asynchronem Code, da Sie die catch-Methode verwenden können, um Fehler zu verwalten, die überall in der Versprechenkette auftreten.

Abschließend können Versprechen Ihren Code vereinfachen, indem sie einen konsistenten, zusammensetzbaren Weg bieten, um asynchrone Operationen unabhängig von ihrer zugrunde liegenden Implementierung zu behandeln.

Wie man ein Promise erstellt

Promise-Syntax:

const myPromise = new Promise((resolve, reject) => {
  // Führe eine asynchrone Operation aus
  // Wenn die Operation erfolgreich ist, rufe resolve mit dem Ergebnis auf
  // Wenn die Operation fehlschlägt, rufe reject mit einem Fehlerobjekt auf
});

myPromise
  .then((result) => {
    // Verarbeite das erfolgreiche Ergebnis
  })
  .catch((error) => {
    // Verarbeite den Fehler
  });
// Beispiel 1, wie man ein Promise erstellt

function myAsyncFunction(): Promise<string> {
  return new Promise<string>((resolve, reject) => {
    // Einige asynchrone Operation
    setTimeout(() => {
      // Erfolgreiche Operation löst das Promise aus. Schau dir meinen neuesten Blogbeitrag über das Meistern von asynchroner Programmierung in TypeScript an! Lerne, wie man mit Promises, Async/Await und Callbacks arbeitet, um effizienten und skalierbaren Code zu schreiben. Mach dich bereit, deine TypeScript-Fähigkeiten auf die nächste Stufe zu heben!
      const success = true;

      if (success) {
        // Löse das Promise mit dem Ergebnisergebnis, wenn die Operation erfolgreich war
        resolve(
          `The result is success and your operation result is ${operationResult}`
        );
      } else {
        const rejectCode: number = 404;
        const rejectMessage: string = `The result is failed and your operation result is ${rejectCode}`;
        // Lehne das Promise mit dem Ergebnisergebnis ab, wenn die Operation fehlgeschlagen ist
        reject(new Error(rejectMessage));
      }
    }, 2000);
  });
}

// Verwende das Promise
myAsyncFunction()
  .then((result) => {
    console.log(result); // Ausgabe: Das Ergebnis ist Erfolg und dein Operationsergebnis ist 4
  })
  .catch((error) => {
    console.error(error); // Ausgabe: Das Ergebnis ist fehlgeschlagen und dein Operationsergebnis ist 404
  });

Im obigen Beispiel haben wir eine Funktion namens myAsyncFunction(), die ein Promise zurückgibt. Wir verwenden den Promise-Konstruktor, um das Versprechen zu erstellen, der eine Callback-Funktion mit den Argumenten resolve und reject verwendet. Wenn die asynchrone Operation erfolgreich ist, rufen wir die resolve-Funktion auf. Wenn sie scheitert, rufen wir die reject-Funktion auf.

Das durch den Konstruktor zurückgegebene Promise-Objekt verfügt über eine Methode namens then(), die Erfolgs- und Fehler-Callback-Funktionen annimmt. Wenn das Promise erfolgreich aufgelöst wird, wird die Erfolgs-Callback-Funktion mit dem Ergebnis aufgerufen. Wenn das Promise abgelehnt wird, wird die Fehler-Callback-Funktion mit einer Fehlermeldung aufgerufen.

Das Promise-Objekt verfügt auch über eine Methode namens catch(), die verwendet wird, um Fehler zu behandeln, die während der Promise-Kette auftreten. Die catch()-Methode nimmt eine Callback-Funktion an, die aufgerufen wird, wenn ein Fehler in der Promise-Kette auftritt.

Jetzt gehen wir dazu über, wie man Promises in TypeScript verkettet.

Wie man Promises verkettet

Das Verketten von Promises ermöglicht es Ihnen, mehrere asynchrone Operationen in Sequenz oder parallel auszuführen. Dies ist hilfreich, wenn Sie mehrere asynchrone Aufgaben nacheinander oder gleichzeitig ausführen müssen. Zum Beispiel müssen Sie möglicherweise Daten asynchron abrufen und sie dann asynchron verarbeiten.

Lassen Sie uns ein Beispiel anschauen, wie man Promises verkettet:

// Beispiel, wie das Verketten von Versprechen funktioniert
// Erstes Versprechen
const promise1 = new Promise((resolve, reject) => {
  const functionOne: string = "This is the first promise function";
  setTimeout(() => {
    resolve(functionOne);
  }, 1000);
});

// Zweites Versprechen
const promise2 = (data: number) => {
  const functionTwo: string = "This is the second second promise  function";
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(` ${data}  '+'  ${functionTwo} `);
    }, 1000);
  });
};

// Verketten des ersten und zweiten Versprechens
promise1
  .then(promise2)
  .then((result) => {
    console.log(result); // Ausgabe: Dies ist die erste Versprechenfunktion + Dies ist die zweite Versprechenfunktion
  })
  .catch((error) => {
    console.error(error);
  });

Im obigen Beispiel haben wir zwei Versprechen: promise1 und promise2. promise1 wird nach 1 Sekunde mit dem String „Dies ist die erste Versprechenfunktion.“ aufgelöst. promise2 nimmt eine Zahl als Eingabe und gibt ein Versprechen zurück, das nach 1 Sekunde mit einem String aufgelöst wird, der die Eingabezahl und den String „Dies ist die zweite Versprechenfunktion.“ kombiniert.

Wir verketten die beiden Versprechen mit der then Methode. Die Ausgabe von promise1 wird als Eingabe an promise2 übergeben. Schließlich verwenden wir erneut die then Methode, um die Ausgabe von promise2 in der Konsole zu protokollieren. Wenn eines der Versprechen, promise1 oder promise2, fehlschlägt, wird der Fehler mit der catch Methode abgefangen.

Herzlichen Glückwunsch! Sie haben gelernt, wie man Versprechen in TypeScript erstellt und verketten kann. Sie können jetzt Versprechen verwenden, um asynchrone Operationen in TypeScript durchzuführen. Jetzt lassen Sie uns erkunden, wie Async/Await in TypeScript funktioniert.

Wie man Async / Await in TypeScript verwendet

Async/await ist eine Syntax, die in ES2017 eingeführt wurde, um die Arbeit mit Promises zu erleichtern. Sie ermöglicht es, asynchronen Code zu schreiben, der aussieht und sich anfühlt wie synchroner Code.

In TypeScript kannst du eine asynchrone Funktion mit dem async-Schlüsselwort definieren. Dies teilt dem Compiler mit, dass die Funktion asynchron ist und ein Promise zurückgibt.

Jetzt sehen wir uns an, wie man async/await in TypeScript verwendet.

Async / Await Syntax:

// Async / Await Syntax in TypeScript
async function functionName(): Promise<ReturnType> {
  try {
    const result = await promise;
    // Code, der nach der Auflösung des Promises ausgeführt wird
    return result;
  } catch (error) {
    // Code, der ausgeführt wird, wenn das Promise abgelehnt wird
    throw error;
  }
}

Im obigen Beispiel ist functionName eine asynchrone Funktion, die ein Promise von ReturnType zurückgibt. Das await-Schlüsselwort wird verwendet, um auf die Auflösung des Promises zu warten, bevor zur nächsten Codezeile übergegangen wird.

Der try/catch-Block wird verwendet, um Fehler zu behandeln, die beim Ausführen des Codes innerhalb der asynchronen Funktion auftreten. Wenn ein Fehler auftritt, wird er vom Catch-Block erfasst, wo du ihn angemessen behandeln kannst.

Verwendung von Pfeilfunktionen mit Async / Await

Du kannst auch Pfeilfunktionen mit der Async/Await-Syntax in TypeScript verwenden:

const functionName = async (): Promise<ReturnType> => {
  try {
    const result = await promise;
    // Code, der nach der Auflösung des Promises ausgeführt wird
    return result;
  } catch (error) {
    // Code, der ausgeführt wird, wenn das Promise abgelehnt wird
    throw error;
  }
};

Im obigen Beispiel ist functionName als Pfeilfunktion definiert, die ein Promise von ReturnType zurückgibt. Das async-Schlüsselwort gibt an, dass es sich um eine asynchrone Funktion handelt, und das await-Schlüsselwort wird verwendet, um auf die Auflösung des Versprechens zu warten, bevor zur nächsten Codezeile übergegangen wird.

Async/Await mit einem API-Aufruf

Jetzt gehen wir über die Syntax hinaus und rufen einige Daten aus einer API mit async/await ab.

interface User {
  id: number;
  name: string;
  email: string;
}

const fetchApi = async (): Promise<void> => {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");

    if (!response.ok) {
      throw new Error(
        `Failed to fetch users (HTTP status code: ${response.status})`
      );
    }

    const data: User[] = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
    throw error;
  }
};

fetchApi();

Hier rufen wir Daten von der JSONPlaceholder-API ab, konvertieren sie in JSON und geben sie dann in der Konsole aus. Dies ist ein Beispiel aus der Praxis, wie man async/await in TypeScript verwendet.

Sie sollten Benutzerinformationen in der Konsole sehen. Dieses Bild zeigt die Ausgabe:

Async/Await mit Axios-API-Aufruf

// Beispiel 2 zur Verwendung von async/await in TypeScript

const fetchApi = async (): Promise<void> => {
  try {
    const response = await axios.get(
      "https://jsonplaceholder.typicode.com/users"
    );
    const data = await response.data;
    console.log(data);
  } catch (error) {
    console.error(error);
  }
};

fetchApi();

Im obigen Beispiel definieren wir die Funktion fetchApi() unter Verwendung von async/await und der Methode Axios.get() zum Senden einer HTTP-GET-Anfrage an die angegebene URL. Wir verwenden await, um auf die Antwort zu warten, extrahieren dann die Daten mithilfe der data-Eigenschaft des Antwortobjekts. Schließlich geben wir die Daten mit console.log() in der Konsole aus. Auftretende Fehler werden eingefangen und mit console.error() in der Konsole protokolliert.

Wir können dies mit Axios erreichen, sodass Sie das gleiche Ergebnis in der Konsole sehen sollten.

Dieses Bild zeigt die Ausgabe bei Verwendung von Axios in der Konsole:

Hinweis: Bevor Sie den obigen Code ausprobieren, müssen Sie Axios mithilfe von npm oder yarn installieren.


npm install axios

yarn add axios

Wenn Sie nicht vertraut sind mit Axios, können Sie hier mehr darüber erfahren.

Sie können sehen, dass wir einen try und catch Block verwendet haben, um Fehler zu behandeln. Der try und catch Block ist eine Methode zur Verwaltung von Fehlern in TypeScript. Also, immer wenn Sie API-Aufrufe machen wie gerade eben, stellen Sie sicher, dass Sie einen try und catch Block verwenden, um Fehler zu behandeln.

Jetzt wollen wir eine fortgeschrittenere Verwendung des try und catch Blocks in TypeScript erkunden:

// Beispiel 3, wie man async / await in TypeScript verwendet

interface Recipe {
  id: number;
  name: string;
  ingredients: string[];
  instructions: string[];
  prepTimeMinutes: number;
  cookTimeMinutes: number;
  servings: number;
  difficulty: string;
  cuisine: string;
  caloriesPerServing: number;
  tags: string[];
  userId: number;
  image: string;
  rating: number;
  reviewCount: number;
  mealType: string[];
}

const fetchRecipes = async (): Promise<Recipe[] | string> => {
  const api = "https://dummyjson.com/recipes";
  try {
    const response = await fetch(api);

    if (!response.ok) {
      throw new Error(`Failed to fetch recipes: ${response.statusText}`);
    }

    const { recipes } = await response.json();
    return recipes; // Gib das Rezepte-Array zurück
  } catch (error) {
    console.error("Error fetching recipes:", error);
    if (error instanceof Error) {
      return error.message;
    }
    return "An unknown error occurred.";
  }
};

// Rezepte abrufen und protokollieren
fetchRecipes().then((data) => {
  if (Array.isArray(data)) {
    console.log("Recipes fetched successfully:", data);
  } else {
    console.error("Error message:", data);
  }
});

In dem obigen Beispiel definieren wir ein interface Recipe, das die Struktur der Daten, die wir von der API erwarten, umreißt. Wir erstellen dann die Funktion fetchRecipes() unter Verwendung von async/await und der fetch() Methode, um eine HTTP GET-Anfrage an den spezifizierten API-Endpunkt zu senden.

Wir verwenden einen try/catch Block, um Fehler zu behandeln, die während der API-Anfrage auftreten könnten. Wenn die Anfrage erfolgreich ist, extrahieren wir die Daten aus der Antwort unter Verwendung von await und geben sie zurück. Wenn ein Fehler auftritt, überprüfen wir eine Fehlermeldung und geben sie als Zeichenfolge zurück, wenn sie vorhanden ist.

Zuletzt rufen wir die Funktion fetchRecipes() auf und verwenden .then(), um die zurückgegebenen Daten in der Konsole auszugeben. Dieses Beispiel zeigt, wie man async/await mit try/catch-Blöcken verwendet, um Fehler in einem fortgeschritteneren Szenario zu behandeln, in dem wir Daten aus einem Antwortobjekt extrahieren müssen und eine benutzerdefinierte Fehlermeldung zurückgeben müssen.

Dieses Bild zeigt das Ausgabenergebnis des Codes:

Async / Await mit Promise.all

Promise.all() ist eine Methode, die ein Array von Versprechen als Eingabe (eine Iteration) annimmt und ein einzelnes Versprechen als Ausgabe zurückgibt. Dieses Versprechen wird erfüllt, wenn alle Eingabeversprechen erfüllt wurden oder wenn die Eingabeiteration keine Versprechen enthält. Es wird sofort abgelehnt, wenn eines der Eingabeversprechen abgelehnt wird oder wenn Nicht-Versprechen einen Fehler werfen, und es wird mit der ersten Ablehnungsnachricht oder dem Fehler abgelehnt.

// Beispiel zur Verwendung von async/await mit Promise.all
interface User {
  id: number;
  name: string;
  email: string;
  profilePicture: string;
}

interface Post {
  id: number;
  title: string;
  body: string;
}

interface Comment {
  id: number;
  postId: number;
  name: string;
  email: string;
  body: string;
}

const fetchApi = async <T>(url: string): Promise<T> => {
  try {
    const response = await fetch(url);
    if (response.ok) {
      const data = await response.json();
      return data;
    } else {
      throw new Error(`Network response was not ok for ${url}`);
    }
  } catch (error) {
    console.error(error);
    throw new Error(`Error fetching data from ${url}`);
  }
};

const fetchAllApis = async (): Promise<[User[], Post[], Comment[]]> => {
  try {
    const [users, posts, comments] = await Promise.all([
      fetchApi<User[]>("https://jsonplaceholder.typicode.com/users"),
      fetchApi<Post[]>("https://jsonplaceholder.typicode.com/posts"),
      fetchApi<Comment[]>("https://jsonplaceholder.typicode.com/comments"),
    ]);
    return [users, posts, comments];
  } catch (error) {
    console.error(error);
    throw new Error("Error fetching data from one or more APIs");
  }
};

fetchAllApis()
  .then(([users, posts, comments]) => {
    console.log("Users: ", users);
    console.log("Posts: ", posts);
    console.log("Comments: ", comments);
  })
  .catch((error) => console.error(error));

Im obigen Code haben wir Promise.all verwendet, um mehrere APIs gleichzeitig abzurufen. Wenn Sie mehrere APIs abrufen müssen, können Sie Promise.all verwenden, um sie alle auf einmal zu erhalten. Wie Sie sehen können, haben wir map verwendet, um durch das Array von APIs zu iterieren und sie dann an Promise.all zu übergeben, um sie gleichzeitig abzurufen.

Das folgende Bild zeigt die Ausgabe der API-Aufrufe:

Lassen Sie uns sehen, wie man Promise.all mit Axios verwendet:

// Beispiel zur Verwendung von async/await mit Axios und Promise.all

const fetchApi = async () => {
  try {
    const urls = [
      "https://jsonplaceholder.typicode.com/users",
      "https://jsonplaceholder.typicode.com/posts",
    ];
    const responses = await Promise.all(urls.map((url) => axios.get(url)));
    const data = await Promise.all(responses.map((response) => response.data));
    console.log(data);
  } catch (error) {
    console.error(error);
  }
};

fetchApi();

Im obigen Beispiel verwenden wir Promise.all, um Daten gleichzeitig von zwei verschiedenen URLs abzurufen. Zuerst erstellen wir ein Array von URLs, dann verwenden wir die Map, um ein Array von Promises aus den axios.get-Aufrufen zu erstellen. Wir übergeben dieses Array an Promise.all, das ein Array von Antworten zurückgibt. Schließlich verwenden wir die Map erneut, um die Daten aus jeder Antwort zu extrahieren und sie in der Konsole auszugeben.

Wie man Callbacks in TypeScript verwendet

Ein Callback ist eine Funktion, die als Argument an eine andere Funktion übergeben wird. Die Callback-Funktion wird innerhalb der anderen Funktion ausgeführt. Callbacks stellen sicher, dass eine Funktion nicht ausgeführt wird, bevor eine Aufgabe abgeschlossen ist – aber dass sie dann direkt nach dem Abschluss der Aufgabe ausgeführt wird. Sie helfen uns, asynchronen JavaScript-Code zu schreiben und Probleme und Fehler zu vermeiden.

// Beispiel für die Verwendung von Callbacks in TypeScript

const add = (a: number, b: number, callback: (result: number) => void) => {
  const result = a + b;
  callback(result);
};

add(10, 20, (result) => {
  console.log(result);
});

Das Bild unten zeigt die Callback-Funktion:

Schauen wir uns ein weiteres Beispiel für die Verwendung von Callbacks in TypeScript an:

// Beispiel für die Verwendung einer Callback-Funktion in TypeScript

type User = {
  name: string;
  email: string;
};

const fetchUserData = (
  id: number,
  callback: (error: Error | null, user: User | null) => void
) => {
  const api = `https://jsonplaceholder.typicode.com/users/${id}`;
  fetch(api)
    .then((response) => {
      if (response.ok) {
        return response.json();
      } else {
        throw new Error("Network response was not ok.");
      }
    })
    .then((data) => {
      const user: User = {
        name: data.name,
        email: data.email,
      };
      callback(null, user);
    })
    .catch((error) => {
      callback(error, null);
    });
};

// Verwendung von fetchUserData mit einer Callback-Funktion
fetchUserData(1, (error, user) => {
  if (error) {
    console.error(error);
  } else {
    console.log(user);
  }
});

Im obigen Beispiel haben wir eine Funktion namens fetchUserData, die eine id und ein Callback als Parameter entgegennimmt. Dieses Callback ist eine Funktion mit zwei Parametern: einem Fehler und einem Benutzer.

Die fetchUserData-Funktion ruft Benutzerdaten von einem JSONPlaceholder-API-Endpunkt unter Verwendung der id ab. Wenn der Abruf erfolgreich ist, wird ein User-Objekt erstellt und mit einem null Fehler an die Callback-Funktion übergeben. Wenn während des Abrufs ein Fehler auftritt, wird der Fehler mit einem null Benutzer an die Callback-Funktion gesendet.

Um die fetchUserData-Funktion mit einem Callback zu verwenden, geben wir eine id und eine Callback-Funktion als Argumente an. Die Callback-Funktion prüft auf Fehler und protokolliert die Benutzerdaten, wenn keine Fehler vorliegen.

Das Bild unten zeigt die Ausgabe der API-Aufrufe:

Wie man Callbacks verantwortungsbewusst verwendet

Während Callbacks grundlegend für asynchrones Programmieren in TypeScript sind, erfordern sie eine sorgfältige Verwaltung, um „Callback-Hölle“ – den pyramidenförmigen, tief verschachtelten Code, der schwer zu lesen und zu warten ist – zu vermeiden. Hier ist, wie man Callbacks effektiv nutzt:

  1. Vermeiden Sie tiefe Verschachtelung

    • Flachen Sie Ihre Code-Struktur, indem Sie komplexe Operationen in benannte Funktionen aufteilen

    • Verwenden Sie Promises oder async/await für komplexe asynchrone Workflows (mehr dazu unten)

  2. Fehlerbehandlung zuerst

    • Folgen Sie immer der Node.js-Konvention von (Fehler, Ergebnis) Parametern

    • Überprüfen Sie Fehler auf jeder Ebene verschachtelter Callbacks

    function processData(input: string, callback: (err: Error | null, result?: string) => void) {
      // ... rufen Sie immer zuerst das Callback mit dem Fehler auf
    }
  1. Verwenden Sie Typannotationen

    • Nutzen Sie das Typsystem von TypeScript, um Callback-Signaturen durchzusetzen

    • Definieren Sie klare Schnittstellen für Callback-Parameter

    type ApiCallback = (error: Error | null, data?: ApiResponse) => void;
  1. Erwägen Sie Kontrollflussbibliotheken
    Für komplexe asynchrone Operationen verwenden Sie Hilfsprogramme wie async.js für:

    • Parallele Ausführung

    • Reihenfolge der Ausführung

    • Fehlerbehandlungspipelines

Wann man Callbacks vs. Alternativen verwenden sollte

Es gibt Zeiten, in denen Callbacks eine gute Wahl sind, und andere Zeiten, in denen sie es nicht sind.

Callbacks sind hilfreich, wenn Sie mit asynchronen Operationen arbeiten (einzeln abgeschlossen), mit älteren Bibliotheken oder APIs zusammenarbeiten, die Callbacks erwarten, Ereignislistener behandeln (wie Klick-Listener oder Websocket-Ereignisse) oder leichtgewichtige Hilfsprogramme mit einfachen asynchronen Anforderungen erstellen.

In anderen Szenarien, in denen Sie sich auf das Schreiben wartbarer Code mit einem klaren asynchronen Fluss konzentrieren müssen, verursachen Callbacks Probleme und Sie sollten Promises oder async-await bevorzugen. Zum Beispiel, wenn Sie mehrere Operationen verketten, komplexe Fehlerpropagation handhaben, mit modernen APIs arbeiten (wie der Fetch-API oder FS Promises) oder promise.all() für parallele Ausführung verwenden müssen.

Beispielhafte Migration von Callbacks zu Promises:

// Rückrufversion
function fetchUser(id: number, callback: (err: Error | null, user?: User) => void) {
  // ... 
}

// Promise-Version
async function fetchUserAsync(id: number): Promise<User> {
  // ...
}

// Verwendung mit async/await
try {
  const user = await fetchUserAsync(1);
} catch (error) {
  // Fehlerbehandlung
}

Die Evolution der Async-Muster

Muster Profis Nachteile
Rückrufe Einfach, universell Verschachtelte Komplexität
Versprechen Kettenfähig, bessere Fehlerfluss Erfordert .then() Ketten
Async/Await Sync-ähnliche Lesbarkeit Erfordert Transpilierung

Moderner TypeScript-Projekte verwenden oft eine Mischung: Rückrufe für ereignisgesteuerte Muster und Versprechen/async-await für komplexe Async-Logik. Der Schlüssel ist die Auswahl des richtigen Werkzeugs für Ihren spezifischen Anwendungsfall und die Aufrechterhaltung der Codeklarheit.

Fazit

In diesem Artikel haben wir verschiedene Möglichkeiten kennengelernt, asynchronen Code in TypeScript zu behandeln. Wir haben über Rückrufe, Versprechen, async/await und deren Verwendung in TypeScript gelernt. Wir haben auch dieses Konzept kennengelernt.

Wenn Sie mehr über das Programmieren und das Werden eines besseren Software-Ingenieurs erfahren möchten, können Sie meinen YouTube-Kanal CliffTech abonnieren.

Vielen Dank, dass Sie meinen Artikel gelesen haben. Ich hoffe, er hat Ihnen gefallen. Wenn Sie Fragen haben, zögern Sie nicht, mich zu kontaktieren.

Verbinden Sie sich mit mir in den sozialen Medien: