📚
Lerndokumentationen
Web
Web
  • Willkommen
  • HTML
    • Was ist HTML?
    • Elemente
    • Attribute
    • Boilerplate
  • Textelemente
  • Links
  • Dokumentenstruktur
  • Medien
  • Tabellen
  • Formulare
  • CSS
    • Was ist CSS?
    • Syntax
  • Einheiten
  • Selektoren
  • Boxmodell
  • Hintergründe und Rahmen
  • Overflow
  • Bilder
  • Formulare
  • Textelemente
  • Layout
    • Flexbox
    • Grid
  • Responsive Design
  • JavaScript
    • Was ist JavaScript?
    • Einbindung in HTML
    • Grundlagen
      • Variablen und Werte
      • Datentypen
      • Operatoren und Ausdrücke
      • Kontrollstrukturen
      • Schleifen
    • Funktionen
      • Funktionsdeklarationen vs. Funktionsausdrücke
      • Arrow Functions
      • Standardparameter und Rest-Parameter
      • First-Class und Higher-Order-Funktionen
      • Closures
      • IIFE (Immediately Invoked Function Expressions)
    • Arrays
      • Erstellen und Modifizieren
      • Iteration über Arrays
      • Sortieren
      • Nützliche Methoden
    • Objekte und Datenstrukturen
      • Erstellen und Manipulieren
      • Destructuring
      • Sets und Maps
    • Strings
      • Template Literals
      • Methoden
    • Moderne JavaScript-Features
      • Optionale Verkettung
      • Nullish Coalescing Operator
      • Spread und Rest Operator
      • Kurzschlussausdrücke
    • Scope und Kontext
      • this Keyword
      • Call, Apply und Bind
      • Hoisting und Temporal Dead Zone (TDZ)
    • Objektorientierte Programmierung
      • Prototypes
      • Constructor Functions
      • ES6 Classes
      • Die create()-Methode
    • Asynchronous JavaScript
      • AJAX
      • Promises
    • Zahlen, Daten, Internationalisierung und Timer
      • Mathematische Operationen
      • Datum und Zeit
      • Internationalisierung
      • Timer
    • Modules
    • JavaScript im Browser (DOM und Events)
      • Das DOM
      • Elemente auswählen, erstellen und manipulieren
      • Styles, Attribute und Klassen
      • Events und Event Listener
      • Event Propagation
        • Event Delegation
      • DOM Traversing
    • JavaScript Engine und Performance
      • Execution Context und Call Stack
  • TypeScript
    • Was ist TypeScript?
  • Compiler und Runtimes
  • Konfiguration
  • Types
    • Primitive Typen und Typableitung
    • Arrays und Tupel
    • Objekte
    • Top- und Bottom-Types
    • Enums
    • Utility Types
      • Records
  • Typenkombination
    • Union Types
    • Discriminated Unions
    • Intersections
  • Funktionen
  • Klassen
    • Grundlagen
    • Feldinitialisierer
    • Schreibgeschützte Felder
    • Implementieren
    • Private und Geschützte Member
    • Getter und Setter
    • Statische Member
    • Abstrakte Klassen und Member
  • Modules
    • Importieren und Exportieren
    • Ambient Types
    • Namespaces
    • Globals
  • React
    • Was ist React?
    • JSX
    • Komponenten
      • Root-Komponente
      • Styling
      • Listen
      • Conditional Rendering
      • Fragments
    • Props
      • Destructuring
      • Children
    • Interaktivität
      • Event Handling
      • State
      • Formulare
    • State Management
      • State anheben
      • Derived State
    • Komposition und Reusability
      • Komponentenstrukturierung
      • Prop Drilling
      • Komposition
Bereitgestellt von GitBook
Auf dieser Seite
  • Lifecycle
  • Consuming Promises
  • Chaining Promises
  • Rejected Promises
  • Throwing errors manually
  • async/await
  • Building Promises
  • Promisifying
  • Promises parallel ausführen
  1. JavaScript
  2. Asynchronous JavaScript

Promises

VorherigeAJAXNächsteZahlen, Daten, Internationalisierung und Timer

Zuletzt aktualisiert vor 3 Monaten

Ein Promise ist ein Objekt, das als Platzhalter für das zukünftige Ergebnis einer asynchronen Operation verwendet wird. Ein Beipsiel für ein zukünftiges Ergebnis bspw. die Response von einem AJAX Call.

Lifecycle

Ein Promise geht durch mehrere Status, weshalb wir einen Lifecycle durchlaufen.

In unserem Code können wir diese verschiedenen States verarbeiten!

Consuming Promises

Wir können Promises über die then()-Methode konsumieren und so die verschiedenen States behandeln.

const getCountryData = (country) => {
  fetch(`https://restcountries.com/v2/name/${country}`)
    .then((response) => response.json())
    .then((data) => renderCountry(data[0]));
};

getCountryData('portugal');

Die Methode response.json() gibt ebenfalls ein Promise zurück, weshalb wir diesen Promise mit einem zweiten then() behandeln müssen.

Chaining Promises

Damit wir die Callback Hell verhindern können wir Promises verketten. Das machen wir indem wir den nächsten Promise zurückgeben und danach wieder mit der Methode then() behandeln.

const getCountryData = (country) => {
  fetch(`https://restcountries.com/v2/name/${country}`)
    .then((response) => response.json())
    .then((data) => {
      renderCountry(data[0]);

      const neighbour = data[0].borders?.[0];
      if (!neighbour) return;

      return fetch(`https://restcountries.com/v2/alpha/${neighbour}`);
    })
    .then((response) => response.json())
    .then((data) => renderCountry(data, 'neighbour'));
};

getCountryData('portugal');

Rejected Promises

Wir können mit der catch()-Methode rejected Promises abfangen.

const renderError = (message) => {
  countriesContainer.insertAdjacentText('beforeend', message);
  countriesContainer.style.opacity = 1;
};

const getCountryData = (country) => {
  fetch(`https://restcountries.com/v2/name/${country}`)
    ...
    .catch((err) => {
      console.error(`🔴 ${err}`);
      renderError(err.message);
    });
};

Throwing errors manually

Wenn der User bspw. Informationen über ein Land will das gar nicht existiert, lautet die Fehlermeldung:

Cannot read property 'flag' of undefined

Das bringt dem Nutzer nicht gerade viel. Wenn wir aber einen manuellen Fehler werfen, können wir so die Message darin selbst bestimmen.

const getJSON = (url, errorMessage = 'Something went wrong') => {
  return fetch(url).then((response) => {
    if (!response.ok) throw new Error(`${errorMessage} (${response.status})`);
    return response.json();
  });
};

const getCountryData = (country) => {
  getJSON(`https://restcountries.com/v2/name/${country}`, 'Country not found')
    .then((data) => {
      renderCountry(data[0]);

      const neighbour = data[0].borders?.[0];
      if (!neighbour) throw new Error('No neighbour found!');

      return getJSON(
        `https://restcountries.com/v2/alpha/${neighbour}`,
        'Country not found'
      );
    })
    .then((data) => renderCountry(data, 'neighbour'))
    .catch((err) => {
      console.error(`🔴 ${err}`);
      renderError(err.message);
    });
};

Wenn wir manuell einen Fehler werfen, dann wird der Promise sofort rejected und wird dann schlussendlich im catch() abgefangen und behandlelt.

async/await

Mit async/await bietet uns JavaScript eine einfachere Möglichkeit mir Promises zu arbeiten.

const whereAmI =  () => {
  const {
    coords: { latitude: lat, longitude: lng }
  } =  getPosition();

  const geoLocationResponse = await fetch(
    `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lng}`
  );
  const locationData = await geoLocationResponse.json();

  const countryResponse = await fetch(
    `https://restcountries.com/v2/name/${locationData.countryName}`
  );
  const [countryData] = await countryResponse.json();

  renderCountry(countryData);
};

whereAmI('portugal');

try...catch

Mit async/await können wir nicht mehr die catch()-Methode nutzen. Deshalb müssen wir hier mit try...catch-Statements arbeiten.

const whereAmI = async () => {
   {
    ...
    
    const geoLocationResponse = await fetch(
      `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lng}`
    );
    if (!geoLocationResponse.ok)
      
      
    ...
    
    const countryResponse = await fetch(
      `https://restcountries.com/v2/name/${locationData.countryName}`
    );
    if (!countryResponse.ok) throw new Error('Problem getting country');

    ...
  }  {
    console.error(`🔴 ${err}`);
    renderError(err.message);
  }
};

return-Werte

async-Funktionen können natürlich auch return-Werte haben. Diese sind aber nur über einen Trick zu erhalten.

(async () => {
  try {
    const city = await whereAmI();
    console.log(city);
  } catch (err) {
    console.error(`🔴 ${err}`);
  }
})();

Den try/catch-Teil brauchen wir nur, wenn wir in der asynchronen Funktion den Error wieder werfen:

catch (err) {
    console.error(`🔴 ${err}`);
    renderError(err.message);
    throw err;
}

In Modules, kann auch ein top-level await genutzt werden, das heisst, man braucht keine IIFE mehr.

const getLastPost = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const data = await res.json();
  
  return { title: data.at(-1).title, text: data.at(-1).body };
}

const lastPost = 

Building Promises

const lotteryPromise = new Promise((resolve, reject) => {
  console.log('The odds are calculated 🔮');

  setTimeout(() => {
    if (Math.random() >= 0.5) {
      resolve('You win 💰');
    } else {
      reject(new Error('You lost 💩'));
    }
  }, 2000);
});

lotteryPromise
  .then((res) => console.log(res))
  .catch((err) => console.error(err));

Über den Promise-Constructor können wir einen neuen Promise erstellen. Die Callback-Funktion darin nimmt zwei Funktionen an:

  • resolve: Markiert den Promise als fullfilled

  • reject: Markiert den Promise als rejected

Diesen Promise können wir dann ganz normal über die then()-Methode konsumieren.

Promisifying

Das Bauen eigener Promises ist vor allem dann nützlich, wenn wir mit Callbacks arbeiten, z.B. bei der setTimeout()-Methode oder mit der Geolocation API. So können wir nämlich der Callback Hell selbst entkommen.

const getPosition = () => {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(resolve, reject);
  });
};

getPosition().then((pos) => console.log(pos));

Promises parallel ausführen

Wenn wir einfach nur sturr mehrere awaits hintereinander ausführen, die aber nicht voneinander abhängig sind, dann verlieren wir kostbare Zeit. Um dies zu umgehen, können wir Promise.all() benutzen. Diese Methode führt alle Calls gleichzeitig aus.

const getCapitals = async (...countries) => {
  try {
    const data = await Promise.all(
      countries.map((country) =>
        getJSON(`https://restcountries.com/v2/name/${country}`)
      )
    );

    return data.map((country) => country[0].capital);
  } catch (err) {
    console.error(err);
  }
};

(async () => {
  const capitals = await getCapitals('portugal', 'tanzania', 'canada');
  console.log(capitals);
})();

Wir nutzen also , um await ausführen zu können. So können wir direkt auf die Daten zugreifen.

IIFE
Promise Lifecylcle
Drawing