JavaScript Promise

Bevor Sie dieses Kapitel durcharbeiten, müssen Sie verstehen, was asynchrone Programmierung ist. Sie können sich Folgendes ansehen:Asynchrone Programmierung in JavaScript

Promise ist eine von ECMAScript 6 bereitgestellte Klasse, die entwickelt wurde, um komplexe asynchrone Aufgaben eleganter zu schreiben.

Promise ist ein Objekt in JavaScript, das verwendet wird, um asynchrone Operationen zu behandeln. Es stellt den letztendlichen Abschluss (oder Fehlschlag) einer asynchronen Operation und ihren resultierenden Wert dar.

Einfach ausgedrückt ist ein Promise ein "Versprechen", dass zu einem späteren Zeitpunkt ein Ergebnis zurückgegeben wird (entweder ein erfolgreiches Ergebnis oder ein Grund für das Scheitern).

Ein Promise hat drei Zustände:

  • pending: Anfangszustand, weder fulfilled noch rejected
  • fulfilled: bedeutet, dass die Operation erfolgreich abgeschlossen wurde
  • rejected: bedeutet, dass die Operation fehlgeschlagen ist

Beispiel

const myPromise = new Promise((resolve, reject) => {
  // asynchroner Operationscode
 
  if (/* Operation erfolgreich */) {
    resolve('Erfolgreiches Ergebnis'); // Promise-Status in erfüllt ändern
  } else {
    reject('Fehlergrund'); // Promise-Status in abgelehnt ändern
  }
});

Browser-Unterstützung

Da Promise in ES6 neu hinzugefügt wurde, unterstützen einige ältere Browser es nicht. Apple Safari 10 und Windows Edge 14 und höher begannen, ES6-Funktionen zu unterstützen.

Das Folgende zeigt die Browser-Unterstützung für Promise:

Chrome 58 Edge 14 Firefox 54 Safari 10 Opera 55

Verwendung von Promise

then()-Methode

then()Diese Methode wird verwendet, um Callback-Funktionen anzugeben, wenn der Promise-Zustand auf erfüllt oder abgelehnt wechselt.

Beispiel

myPromise.then(
  (result) => {
    // Erfolgsfall behandeln
    console.log('Erfolg:', result);
  },
  (error) => {
    // Fehlerfall behandeln
    console.error('Fehler:', error);
  }
);

catch()-Methode

catch()Diese Methode wird speziell verwendet, um Fälle zu behandeln, in denen das Promise abgelehnt wird.

Beispiel

myPromise
  .then((result) => {
    console.log('Erfolg:', result);
  })
  .catch((error) => {
    console.error('Fehler:', error);
  });

finally()-Methode

finally()Diese Methode wird unabhängig vom endgültigen Zustand des Promise ausgeführt.

Beispiel

myPromise
  .then((result) => {
    console.log('Erfolg:', result);
  })
  .catch((error) => {
    console.error('Fehler:', error);
  })
  .finally(() => {
    console.log('Operation abgeschlossen');
  });

Promise-Verkettung

Eine leistungsstarke Eigenschaft von Promise ist, dass mehrere asynchrone Operationen verkettet werden können.

Beispiel

doFirstThing()
  .then((result) => doSecondThing(result))
  .then((newResult) => doThirdThing(newResult))
  .then((finalResult) => {
    console.log('Endergebnis:', finalResult);
  })
  .catch((error) => {
    console.error('Fehler irgendwo in der Kette:', error);
  });

Statische Promise-Methoden

Promise.all()

Warte, bis alle Promises abgeschlossen sind oder bis ein beliebiges Promise fehlschlägt.

Beispiel

Promise.all([promise1, promise2, promise3])
  .then((results) => {
    // results ist ein Array, das alle Promise-Ergebnisse enthält
    console.log(results);
  })
  .catch((error) => {
    // Wird hier ausgeführt, wenn irgendein Promise fehlschlägt
    console.error(error);
  });

Promise.race()

Gibt das Ergebnis des ersten Promise zurück, das abgeschlossen wird (unabhängig von Erfolg oder Fehlschlag).

Beispiel

Promise.race([promise1, promise2, promise3])
  .then((result) => {
    // Nutze das Ergebnis des ersten abgeschlossenen Promises
    console.log(result);
  })
  .catch((error) => {
    // Wenn das erste abgeschlossene Promise abgelehnt wird
    console.error(error);
  });

Promise.resolve() und Promise.reject()

Schnell ein erfülltes oder abgelehntes Promise erstellen.

Beispiel

const resolvedPromise = Promise.resolve('Immediately resolved value');
const rejectedPromise = Promise.reject('Immediately rejected reason');

Praktische Anwendungsbeispiele

Beispiel 1: Verwenden von Promise zum Verarbeiten von AJAX-Anfragen

Beispiel

function fetchData(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.response);
      } else {
        reject(new Error(xhr.statusText));
      }
    };
    xhr.onerror = () => reject(new Error('Netzwerkfehler'));
    xhr.send();
  });
}

fetchData('https://api.example.com/data')
  .then((data) => {
    console.log('Daten erfolgreich abgerufen:', data);
  })
  .catch((error) => {
    console.error('Fehler beim Abrufen der Daten:', error);
  });

Beispiel 2: Verwenden einer Promise-Kette zum Verarbeiten mehrerer asynchroner Operationen

Beispiel

function getUser(userId) {
  return fetch(`/users/${userId}`);
}

function getPosts(userId) {
  return fetch(`/users/${userId}/posts`);
}

getUser(123)
  .then((user) => {
    console.log('Benutzerinformationen werden abgerufen:', user);
    return getPosts(user.id);
  })
  .then((posts) => {
    console.log('Benutzerbeiträge werden abgerufen:', posts);
  })
  .catch((error) => {
    console.error('Vorgang fehlgeschlagen:', error);
  });

Häufige Probleme und bewährte Verfahren

1. Promise-Verschachtelung vermeiden

Falscher Ansatz (die Promise-Version der Callback-Hölle):

Beispiel

doFirstThing().then((firstResult) => {
  doSecondThing(firstResult).then((secondResult) => {
    doThirdThing(secondResult).then((thirdResult) => {
      console.log(thirdResult);
    });
  });
});

Richtiger Ansatz (Verkettung verwenden):

Beispiel

doFirstThing()
  .then(doSecondThing)
  .then(doThirdThing)
  .then((finalResult) => {
    console.log(finalResult);
  });

2. Ablehnungen immer behandeln

Wenn du vergisst, Promise-Ablehnungen zu behandeln, führt das zu Fehlern vom Typ "uncaught promise rejection". Verwende immer.catch()odertry/catch(bei async/await), um Fehler zu behandeln.

3. Promises sind nicht abbrechbar

Sobald ein Promise erstellt wurde, kann es nicht abgebrochen werden. Wenn du eine Abbruchfunktion benötigst, ziehe die Verwendung von AbortController oder anderen Mustern in Betracht.

4. FAQ

F: Kann die Reihenfolge von then, catch und finally umgekehrt werden?

A: Ja, der Effekt ist genau derselbe. Aber es wird nicht empfohlen; am besten schreibt man das Programm in der Reihenfolge then-catch-finally.

F: Können außer dem then-Block die anderen beiden Blöcke mehrfach verwendet werden?

A: Ja. finally wird, wie then, der Reihe nach ausgeführt, aber nur der erste catch-Block wird ausgeführt, es sei denn, im catch-Block tritt eine Ausnahme auf. Daher ist es am besten, nur einen catch- und einen finally-Block vorzusehen.

F: Wie unterbricht man einen then-Block?

A: Ein then-Block wird standardmäßig sequenziell nach unten ausgeführt; return kann ihn nicht unterbrechen. Sie können throw verwenden, um zu catch zu springen, um die Unterbrechung zu erreichen.

F: Wann ist es angemessen, Promise anstelle traditioneller Callback-Funktionen zu verwenden?

A: Wenn mehrere asynchrone Operationen sequenziell ausgeführt werden müssen. Wenn Sie beispielsweise einen Benutzernamen und ein Passwort nacheinander über asynchrone Methoden prüfen möchten, müssen Sie zuerst den Benutzernamen asynchron prüfen und dann das Passwort asynchron prüfen — das ist eine Situation, die sich gut für Promise eignet.

F: Ist Promise eine Methode, um Asynchrones in Synchrones umzuwandeln?

A: Überhaupt nicht. Promise ist nur ein besserer Programmierstil.

F: Wann müssen wir ein weiteres then schreiben, anstatt die Programmierung im aktuellen then fortzusetzen?

A: Wenn Sie eine weitere asynchrone Aufgabe aufrufen müssen.


Promise und async/await

ES2017 führte async/await ein, das auf Promise basiert und eine intuitivere Syntax für die Handhabung asynchroner Operationen bietet.

Beispiel

async function fetchData() {
  try {
    const user = await getUser(123);
    const posts = await getPosts(user.id);
    console.log('User posts:', posts);
  } catch (error) {
    console.error('Fehler beim Abrufen der Daten:', error);
  }
}

Obwohl async/await besser lesbar ist, ist das Verständnis der grundlegenden Konzepte von Promise nach wie vor sehr wichtig, denn es ist die Grundlage von async/await.

Andere Erweiterungen