{}const=>[]async()letfn</>var
EntwicklungJS

Promises in JavaScript: Der ultimative Leitfaden für Asynchronität

Verstehen von Promise in JavaScript: drei Zustände von Promises, then/catch/finally-Ketten, Promise.all- und Promise.race-Methoden. Praktische Beispiele, typische Fehler und Best Practices für die Arbeit mit asynchronem Code für Entwickler.

К

Kodik

Autor

6 Min. Lesezeit

Was ist Promise?

Promise ist ein Objekt, das das Ergebnis einer asynchronen Operation darstellt, die jetzt, in der Zukunft oder nie erhalten werden kann. Dies ist eine Art "Versprechen", das Ergebnis zurückzugeben, wenn die Operation abgeschlossen ist.

Promis existiert in einem von drei Zuständen:

  • pending (Warten) — Anfangszustand, Vorgang wird noch ausgeführt

  • fulfilled (abgeschlossen) — Vorgang erfolgreich abgeschlossen

  • rejected (abgelehnt) — Operation mit Fehler beendet

Es ist wichtig zu verstehen, dass ein Versprechen nur einmal aus dem Status pending in den Status fulfilled oder rejected übergehen kann. Danach ändert sich der Status nicht mehr.

🔥 100.000+ Schüler sind bereits bei uns

Genug Theorie gelesen?
Zeit zu coden!

Kodik — eine App, in der du durch Praxis programmieren lernst. KI-Mentor, interaktive Lektionen, echte Projekte.

🤖 KI 24/7
🎓 Zertifikate
💰 Kostenlos
🚀 Jetzt starten
Heute beigetreten

Erstellen eines Versprechens

Ein Promis wird mit dem Konstruktor Promise erstellt, der eine Executor-Funktion akzeptiert. Diese Funktion erhält zwei Argumente: resolve und reject.

const myPromise = new Promise((resolve, reject) => {
  // Asynchrone Operation
  const success = true;
  
  if (success) {
    resolve('The operation was successful!');
  } else {
    reject('An error occurred');
  }
});

Die Executor-Funktion wird sofort gestartet, wenn ein Promis erstellt wird. Wenn Sie resolve(value) aufrufen, wechselt das Versprechen in den Zustand fulfilled mit dem Ergebnis value. Beim Aufruf von reject(error) geht das Promis mit dem Fehler error in rejected über.

Ergebnisverarbeitung: then, catch, finally

Die Methoden then, catch und finally werden verwendet, um mit dem Ergebnis des Promises zu arbeiten.

myPromise
  .then(result => {
    console.log('Success:', result);
    return result.toUpperCase();
  })
  .catch(error => {
    console.error('Error:', error);
  })
  .finally(() => {
    console.log('Operation completed');
  });

Die Methode then akzeptiert zwei optionale Argumente: einen Callback für eine erfolgreiche Ausführung und einen Callback für einen Fehler. In der Praxis wird catch häufiger verwendet, um Fehler zu behandeln, was den Code lesbarer macht.

Die Methode finally wird immer ausgeführt, unabhängig vom Ergebnis des Versprechens. Dies ist praktisch für Aktionen, die in jedem Fall ausgeführt werden müssen, z. B. das Ausblenden der Ladeanzeige.

Promis-Ketten

Einer der Hauptvorteile von Promises ist die Möglichkeit, Ketten asynchroner Operationen zu erstellen. Jeder then gibt ein neues Versprechen zurück, mit dem Sie Sequenzen erstellen können.

fetch('https://api.example.com/user/1')
  .then(response => response.json())
  .then(user => {
    console.log('Username:', user.name);
    return fetch(`https://api.example.com/user/${user.id}/posts`);
  })
  .then(response => response.json())
  .then(posts => {
    console.log('User posts:', posts);
  })
  .catch(error => {
    console.error('Error in the chain:', error);
  });

In der Kette der Promises "fällt" ein Fehler in jeder Phase bis zum nächsten catch. Auf diese Weise können Fehler zentral behandelt werden.

Praktisches Beispiel: Daten laden

Betrachten wir ein reales Szenario - das Laden von Benutzerdaten vom Server mit der Verarbeitung verschiedener Situationen.

function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    // Simulation von Netzwerkverzögerungen
    setTimeout(() => {
      const users = {
        1: { name: 'Alexey', role: 'developer' },
        2: { name: 'Maria', role: 'designer' }
      };
      
      const user = users[userId];
      
      if (user) {
        resolve(user);
      } else {
        reject(new Error('User not found'));
      }
    }, 1000);
  });
}

// Anwendung
fetchUserData(1)
  .then(user => {
    console.log(`Hi ${user.name}!`);
    console.log(`Your role: ${user.role}`);
  })
  .catch(error => {
    console.error('Failed to load data:', error.message);
  })
  .finally(() => {
    console.log('Request completed');
  });

Promise.all und Promise.race

JavaScript bietet nützliche statische Methoden für die Arbeit mit mehreren Promises.

Promise.all

Die Methode Promise.all nimmt ein Array von Promises an und gibt ein neues Promise zurück, das ausgeführt wird, wenn alle Promises im Array ausgeführt wurden. Wenn mindestens ein Versprechen abgelehnt wird, wird der gesamte Promise.all abgelehnt.

const promise1 = Promise.resolve(3);
const promise2 = new Promise(resolve => setTimeout(() => resolve(42), 1000));
const promise3 = fetch('https://api.example.com/data').then(r => r.json());

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log('All results:', results);
    // results wird ein Array sein: [3, 42, {...Daten aus der API}]
  })
  .catch(error => {
    console.error('One of the promisses ended in error:', error);
  });

Dies ist nützlich, wenn Sie mehrere unabhängige asynchrone Operationen ausführen und auf alle warten müssen.

Promise.race

Die Methode Promise.race gibt ein Versprechen zurück, das ausgeführt oder abgelehnt wird, sobald das erste der übergebenen Versprechen ausgeführt oder abgelehnt wird.

const slowPromise = new Promise(resolve => 
  setTimeout(() => resolve('Slow'), 3000)
);
const fastPromise = new Promise(resolve => 
  setTimeout(() => resolve('Fast'), 1000)
);

Promise.race([slowPromise, fastPromise])
  .then(result => {
    console.log('Winner:', result); // 'Schnell'});

Dies ist nützlich, um Timeouts zu implementieren oder die schnellste Datenquelle auszuwählen.

Promise.allSettled und Promise.any

Moderne Versionen von JavaScript haben zwei weitere nützliche Methoden hinzugefügt.

Promise.allSettled

Im Gegensatz zu Promise.all wartet die Methode Promise.allSettled unabhängig vom Ergebnis auf den Abschluss aller Promises. Gibt ein Array von Objekten mit Informationen zu jedem Versprechen zurück.

const promises = [
  Promise.resolve('Success'),
  Promise.reject('Error'),
  Promise.resolve('More success')
];

Promise.allSettled(promises)
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Promis ${index}: executed with value ${result.value}`);
      } else {
        console.log(`Promo ${index}: rejected with reason ${result.reason}`);
      }
    });
  });

Promise.any

Die Methode Promise.any gibt die erste erfolgreich ausgeführte Promesse zurück. Wenn alle Promises abgelehnt werden, wird das abgelehnte Promise mit einem aggregierten Fehler zurückgegeben.

const promises = [
  Promise.reject('Error 1'),
  Promise.resolve('Success'),
  Promise.reject('Error 2')
];

Promise.any(promises)
  .then(result => {
    console.log('First successful result:', result); // 'Erfolg's'
  })
  .catch(error => {
    console.error('All promissory notes are rejected:', error);
  });

Typische Fehler bei der Arbeit mit Promises

Vergessene Rückgabe in der Kette

Einer der häufigsten Fehler ist, zu vergessen, den Prom aus then zurückzugeben, was die Kette unterbricht.

// Falsch
fetchUser()
  .then(user => {
    fetchPosts(user.id); // Sie haben die Rückgabe vergessen!
  })
  .then(posts => {
    // Beiträge werden nicht definiert
    console.log(posts);
  });

// Richtig
fetchUser()
  .then(user => {
    return fetchPosts(user.id); // Wir geben die Prämie zurück
  })
  .then(posts => {
    console.log(posts); // Posts enthält jetzt Daten
  });

Verschachtelte Promises anstelle von Ketten

Manchmal erstellen Entwickler verschachtelte Promises, was uns zum Problem des Callback-Hells zurückführt.

// Schlecht - Verschachtelung
fetchUser()
  .then(user => {
    fetchPosts(user.id)
      .then(posts => {
        fetchComments(posts[0].id)
          .then(comments => {
            console.log(comments);
          });
      });
  });

// Gut — Kette
fetchUser()
  .then(user => fetchPosts(user.id))
  .then(posts => fetchComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(error => console.error(error));

Fehlende Fehlerbehandlung

Fügen Sie immer catch hinzu, um Fehler zu behandeln, da sie sonst möglicherweise nicht bemerkt werden.

// Gefährlich
fetchData().then(data => console.log(data));

// Sicher
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error('An error occurred:', error));

Von Promises zu Async/Await

Promises legten den Grundstein für die Syntax von async/await, die asynchronen Code noch synchroner macht.

// Mit Versprechen
function getUserInfo() {
  return fetchUser()
    .then(user => fetchPosts(user.id))
    .then(posts => {
      return { user, posts };
    });
}

// Mit async/await
async function getUserInfo() {
  const user = await fetchUser();
  const posts = await fetchPosts(user.id);
  return { user, posts };
}

Das Verständnis von Promises ist jedoch von entscheidender Bedeutung, da async/await ein syntaktischer Zucker für Promises ist und das Wissen über ihre Funktionsweise hilft, Asynchronität in JavaScript effektiv zu nutzen.

Befund

Promises lösen ein grundlegendes Problem von JavaScript - die elegante Arbeit mit asynchronen Operationen. Sie bieten eine intuitive Schnittstelle für die Steuerung von Aktionssequenzen, die Fehlerbehandlung und die Zusammensetzung asynchroner Operationen.

Wichtige Punkte, die man sich merken sollte:

  • Promis befindet sich in einem von drei Zuständen und ändert ihn nur einmal

  • Promises-Ketten lösen das Problem der Callback-Verschachtelung

  • Behandeln Sie Fehler immer mit catch

  • Verwenden Sie Promise.all, um unabhängige Operationen parallel auszuführen

  • Geben Sie die Promises von then zurück, um die richtigen Ketten zu erstellen

Ein tiefes Verständnis von Promises ist die Grundlage für die Arbeit mit modernem asynchronem JavaScript und den Übergang zu async/await.

Möchten Sie Ihr Wissen systematisieren? Auf der Plattform Kodik finden Sie praktische Programmierkurse mit Zertifikat nach Abschluss der Ausbildung.

Schließen Sie sich unserem gemütlicher Telegram-Kanal — Hier teilen wir nützliche Materialien, diskutieren interessante Themen und helfen Entwicklerneulingen, sich beruflich weiterzuentwickeln. Gemeinsam lernt es sich besser!

🎯Hör auf zu zögern

Artikel gefallen?
Zeit zum Üben!

Bei Kodik liest du nicht nur — du schreibst sofort Code. Theorie + Praxis = echte Skills.

Sofortige Praxis
🧠KI erklärt Code
🏆Zertifikat

Keine Registrierung • Keine Karte