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.
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 funktioniert, gibt das Versprechen einen Fehler zurück.
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. Ablehnen dient dazu, das Versprechen abzulehnen, falls bei der Auswertung unserer Logik ein Fehler auftritt.
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.
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 Catch-Methode 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.
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, ob eines der Versprechen einen Fehler zurückgibt.
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 gelö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 eine Reihe von Versprechen und gibt eine Reihe von Ergebnissen zurück. Wenn eines der Versprechen abgelehnt wird, wird auch Promise.all abgelehnt.
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.
Wie Sie sehen, erfordert das Schreiben von Promises viel Standardcode. 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.
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();
Our fetchData is marked as async and it allows us to use await to handle asynchronous calls inside the function. We call more Promises and they will evaluated one after the other.
We use try...catch block if we want handle the errors. Rejected error is then caught in the catch block and we can act on it like logging the error.
They are both features of JavaScript handling with asynchronous code. The main difference is in the syntax when Promises use chaining with then and catch but async await syntax is more in synchronous way. It makes it easier to read. Error handling for async await is more straightforward when it leverages try...catch block. This is a question that you can easily get at the interview. During the answer, you can get deeper into the description of both and highlight those differences.
Promise features
Of course, you can use all the features with async await. For example 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); } };
Promises are a fundamental feature in JavaScript for handling asynchronous code. Here are the main ways it is used:
As was already shown in the examples above, this is one of the most used use cases for Promises and you work with it daily.
Reading and writing files asynchronously can be done using promises, especially by Node.js module 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);
Axios is library that you should be familiar with. Axios handles HTTP requests in client and is vastly used.
Express is a web framework for Node.js. It makes it easy to build web apps and APIs, and when you use promises with Express, your code stays clean and easy to manage.
All the examples can be found at: https://github.com/PrincAm/promise-example
Promises are a fundamental part of JavaScript, essential for handling asynchronous tasks in web development. Whether fetching data, working with files, or using popular libraries like Axios and Express, you’ll frequently use promises in your code.
In this article, we explored what Promises are, how to define and retrieve their results, and how to handle errors effectively. We also covered key features like chaining, Promise.all, and Promise.race. Finally, we introduced async await syntax, which offers a more straightforward way to work with promises.
Understanding these concepts is crucial for any JavaScript developer, as they are tools you’ll rely on daily.
If you haven’t tried it yet, I recommend writing a simple code snippet to fetch data from an API. You can start with a fun API to experiment with. Plus, all the examples and code snippets are available in this repository for you to explore.
Das obige ist der detaillierte Inhalt vonVersprechen in JavaScript: Asynchronen Code verstehen, handhaben und beherrschen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!