„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Versprechen in JavaScript: Asynchronen Code verstehen, handhaben und beherrschen

Versprechen in JavaScript: Asynchronen Code verstehen, handhaben und beherrschen

Veröffentlicht am 07.11.2024
Durchsuche:647

Promises in JavaScript: Understanding, Handling, and Mastering Async Code

Einführung

Ich habe früher als Java-Entwickler gearbeitet und erinnere mich an das erste Mal, als ich mit Versprechen in JavaScript in Berührung kam. Obwohl das Konzept einfach schien, konnte ich immer noch nicht ganz verstehen, wie Promises funktioniert. Das änderte sich, als ich anfing, sie in Projekten einzusetzen und die Fälle verstand, die sie lösten. Dann kam der AHA-Moment und alles wurde klarer. Mit der Zeit wurden Promises zu einer wertvollen Waffe an meinem Werkzeuggürtel. Es ist seltsam befriedigend, wenn ich sie bei der Arbeit verwenden und die asynchrone Handhabung zwischen Funktionen lösen kann.

Wahrscheinlich stoßen Sie zuerst auf Promises, wenn Sie Daten von einer API abrufen, was auch das häufigste Beispiel ist. Kürzlich wurde ich interviewt und rate mal, was die erste Frage war: „Können Sie mir den Unterschied zwischen Promise und Async Await erklären?“. Ich begrüße das, weil ich es als einen guten Ausgangspunkt sehe, um besser zu erfahren, wie der Antragsteller die Funktionsweise der Mechanismen versteht. Allerdings verwendet er oder sie meist andere Bibliotheken und Frameworks. Dadurch konnte ich die Unterschiede aufschreiben und bewährte Vorgehensweisen für den Umgang mit asynchronen Funktionsfehlern beschreiben.

Was ist das Versprechen?

Beginnen wir mit der ersten Frage: „Was ist das Versprechen?“ Promise ist ein Platzhalter für den Wert, den wir noch nicht kennen, aber wir werden ihn als Ergebnis einer asynchronen Berechnung/Funktion erhalten. Wenn das Versprechen gut geht, werden wir das Ergebnis bekommen. Wenn das Versprechen nicht gut funktioniert, gibt das Versprechen einen Fehler zurück.

Ein einfaches Beispiel für ein Versprechen

Ein Versprechen definieren

Sie definieren Promise, indem Sie seinen Konstruktor aufrufen und zwei Rückruffunktionen übergeben: resolve und reject.

const newPromise = new Promise((resolve, reject) => {
    resolve('Hello');
    // reject('Error');
});

Wir rufen die Auflösungsfunktion auf, wenn wir das Versprechen erfolgreich auflösen möchten. „Reject“ dient dazu, das Versprechen abzulehnen, falls bei der Auswertung unserer Logik ein Fehler auftritt.

Abrufen des Promise-Ergebnisses

Wir verwenden dann die integrierte Funktion, um das Ergebnis des Versprechens zu erhalten. Es gibt zwei übergebene Rückrufe: Ergebnis und Fehler. Das Ergebnis wird aufgerufen, wenn das Promise durch die Funktion „resolve“ erfolgreich aufgelöst wurde. Wenn das Versprechen nicht aufgelöst wird, wird der zweite Funktionsfehler aufgerufen. Diese Funktion wird entweder durch Ablehnung oder durch einen anderen ausgegebenen Fehler ausgelöst.

newPromise.then(result => {
    console.log(result); // Hello
}, error => {
    console.log("There shouldn't be an error");
});

In unserem Beispiel erhalten wir das Ergebnis „Hallo“, weil wir das Versprechen erfolgreich gelöst haben.

Fehlerbehandlung von Versprechen

Wenn das Versprechen abgelehnt wird, wird immer sein zweiter Fehlerrückruf aufgerufen.

const newPromise1 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise1');
});

newPromise1.then(
  (result) => {
    console.log(result); // It is not invoked
  },
  (error) => {
    console.log(error); // 'An error occurred in Promise1'
  }
);

Ein aus Gründen der Übersichtlichkeit empfehlenswerterer Ansatz ist die Verwendung der integrierten Catch-Methode.

const newPromise2 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise2');
});

newPromise2
  .then((result) => {
    console.log(result); // It is not invoked
  })
  .catch((error) => {
    console.log(error); // 'An error occurred in Promise2'
  });
Die Methode

catch ist verkettet und hat einen eigenen Fehlerrückruf bereitgestellt. Es wird aufgerufen, wenn das Versprechen abgelehnt wird.

Beide Versionen funktionieren gut, aber die Verkettung ist meiner Meinung nach besser lesbar und praktisch, wenn andere integrierte Methoden verwendet werden, die wir weiter behandeln.

Versprechen verketten

Das Ergebnis eines Versprechens könnte wahrscheinlich ein weiteres Versprechen sein. In diesem Fall können wir eine beliebige Anzahl von then-Funktionen verketten.

getJSON('categories.json')
    .then(categories => {
        console.log('Fetched categories:', categories);

        return getJSON(categories[0].itemsUrl);
    })
    .then(items => {
        console.log('Fetched items:', items);

        return getJSON(items[0].detailsUrl);
    })
    .then(details => {
        console.log('Fetched details:', details);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

In unserem Beispiel dient es dazu, die Suchergebnisse einzugrenzen, um Detaildaten zu erhalten. Jede then-Funktion kann auch einen eigenen Fehlerrückruf haben. Wenn es uns nur darum geht, Fehler in der Aufrufkette abzufangen, können wir die Catch-Funktion nutzen. Es wird ausgewertet, wenn eines der Versprechen einen Fehler zurückgibt.

Versprich es allen

Manchmal möchten wir auf die Ergebnisse unabhängigerer Versprechen warten und dann auf der Grundlage der Ergebnisse handeln. Wir können die integrierte Funktion Promise.all verwenden, wenn uns die Reihenfolge, in der die Versprechen aufgelöst wurden, egal ist.

Promise.all([
    getJSON('categories.json'),
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techItems = results[1];
        const scienceItems = results[2];

        console.log('Fetched categories:', categories);
        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);

        // Fetch details of the first item in each category
        return Promise.all([
            getJSON(techItems[0].detailsUrl),
            getJSON(scienceItems[0].detailsUrl)
        ]);
    })
    .then(detailsResults => {
        const laptopDetails = detailsResults[0];
        const physicsDetails = detailsResults[1];

        console.log('Fetched laptop details:', laptopDetails);
        console.log('Fetched physics details:', physicsDetails);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Promise.all nimmt ein Array von Versprechen und gibt ein Array von Ergebnissen zurück. Wenn eines der Versprechen abgelehnt wird, wird auch Promise.all abgelehnt.

Rennversprechen

Eine weitere integrierte Funktionalität ist Promise.race. Es wird verwendet, wenn Sie über mehrere asynchrone Funktionen (Promises) verfügen und diese gegeneinander antreten möchten.

Promise.race([
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(result => {
        console.log('First resolved data:', result);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Die Ausführung der Versprechen kann unterschiedlich lange dauern und Promise.race wertet das erste gelöste oder abgelehnte Versprechen aus dem Array aus. Es wird verwendet, wenn uns die Reihenfolge egal ist, wir aber das Ergebnis des schnellsten asynchronen Aufrufs wollen.

Was ist Async Await?

Wie Sie sehen, erfordert das Schreiben von Promises viel Boilerplate-Code. Glücklicherweise verfügen wir über die native Funktion Async Await, die die Verwendung von Promises noch einfacher macht. Wir kennzeichnen eine Funktion mit dem Wort „async“ und sagen damit, dass wir irgendwo im Code eine asynchrone Funktion aufrufen und nicht darauf warten sollten. Anschließend wird die Async-Funktion mit dem Wartewort aufgerufen.

Grundlegendes Beispiel für Async Await

const fetchData = async () => {
    try {
        // Fetch the categories
        const categories = await getJSON('categories.json');
        console.log('Fetched categories:', categories);

        // Fetch items from the first category (Technology)
        const techItems = await getJSON(categories[0].itemsUrl);
        console.log('Fetched technology items:', techItems);

        // Fetch details of the first item in Technology (Laptops)
        const laptopDetails = await getJSON(techItems[0].detailsUrl);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error has occurred:', error.message);
    }
};

fetchData();

Unsere fetchData sind als asynchron markiert und ermöglichen uns die Verwendung von „await“, um asynchrone Aufrufe innerhalb der Funktion abzuwickeln. Wir rufen weitere Promises auf und diese werden nacheinander ausgewertet.

Wir verwenden den try...catch-Block, wenn wir die Fehler behandeln möchten. Der abgelehnte Fehler wird dann im Catch-Block abgefangen und wir können darauf reagieren, als würden wir den Fehler protokollieren.

Was ist anders?

Beide handelt es sich um Funktionen der JavaScript-Verarbeitung mit asynchronem Code. Der Hauptunterschied liegt in der Syntax, wenn Promises eine Verkettung mit then und Catch verwenden, die Syntax von async waiting jedoch eher synchron ist. Es erleichtert das Lesen. Die Fehlerbehandlung für asynchrones Warten ist einfacher, wenn der try...catch-Block genutzt wird. Dies ist eine Frage, die Ihnen im Vorstellungsgespräch leicht gestellt werden kann. Während der Antwort können Sie tiefer in die Beschreibung beider einsteigen und diese Unterschiede hervorheben.

Versprechende Funktionen

Natürlich können Sie alle Funktionen mit Async Wait nutzen. Zum Beispiel Promise.all.

const fetchAllData = async () => {
    try {
        // Use await with Promise.all to fetch multiple JSON files in parallel
        const [techItems, scienceItems, laptopDetails] = await Promise.all([
            getJSON('technology_items.json'),
            getJSON('science_items.json'),
            getJSON('laptops_details.json')
        ]);

        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error occurred:', error.message);
    }
};

Praktische Anwendungsfälle

Promises sind eine grundlegende Funktion in JavaScript für die Verarbeitung von asynchronem Code. Hier sind die wichtigsten Verwendungsmöglichkeiten:

Abrufen von Daten von APIs

Wie bereits in den Beispielen oben gezeigt wurde, ist dies einer der am häufigsten verwendeten Anwendungsfälle für Promises und Sie arbeiten täglich damit.

Behandeln von Dateioperationen

Das asynchrone Lesen und Schreiben von Dateien kann mithilfe von Versprechen erfolgen, insbesondere durch das Node.js-Modul fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

Versprechenbasierte Bibliotheken

Axios ist eine Bibliothek, mit der Sie vertraut sein sollten. Axios verarbeitet HTTP-Anfragen im Client und wird häufig verwendet.

Express ist ein Webframework für Node.js. Es erleichtert das Erstellen von Webanwendungen und APIs, und wenn Sie Versprechen mit Express verwenden, bleibt Ihr Code sauber und einfach zu verwalten.

Repository mit Beispielen

Alle Beispiele finden Sie unter: https://github.com/PrincAm/promise-example

Zusammenfassung

Promises sind ein grundlegender Bestandteil von JavaScript und für die Abwicklung asynchroner Aufgaben in der Webentwicklung unerlässlich. Ob Sie Daten abrufen, mit Dateien arbeiten oder beliebte Bibliotheken wie Axios und Express verwenden, Sie werden in Ihrem Code häufig Versprechen verwenden.

In diesem Artikel haben wir untersucht, was Versprechen sind, wie man ihre Ergebnisse definiert und abruft und wie man effektiv mit Fehlern umgeht. Wir haben auch wichtige Funktionen wie Verkettung, Promise.all und Promise.race behandelt. Schließlich haben wir die asynchrone Wait-Syntax eingeführt, die eine einfachere Möglichkeit bietet, mit Versprechen zu arbeiten.

Das Verständnis dieser Konzepte ist für jeden JavaScript-Entwickler von entscheidender Bedeutung, da es sich um Tools handelt, auf die Sie sich täglich verlassen werden.

Wenn Sie es noch nicht ausprobiert haben, empfehle ich Ihnen, ein einfaches Code-Snippet zu schreiben, um Daten von einer API abzurufen. Sie können mit einer unterhaltsamen API beginnen, mit der Sie experimentieren können. Darüber hinaus stehen Ihnen in diesem Repository alle Beispiele und Codeausschnitte zum Erkunden zur Verfügung.

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/princam/promises-in-javascript-understanding-handling-and-mastering-async-code-10kn?1 Bei Verstößen wenden Sie sich bitte an [email protected] um es zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3