Entwicklung und Integration eines maßgeschneiderten SAP Fiori Launchpad Plugins: Ein umfassender Leitfaden

Die Fähigkeit, Informationen über das aktuelle System und den Mandanten in der SAP Fiori-Oberfläche anzuzeigen, ist von unschätzbarem Wert für Benutzer und Administratoren. In diesem Tutorial wird ein Plugin erstellt, das es Benutzern ermöglicht, auf einen Blick zu erkennen, mit welchem Mandanten sie sich in welcher Systemumgebung befinden.

Für diesen Leitfaden wird ein laufendes SAP System benötigt und Visual Studio Code, mit der Erweiterung „SAP Fiori Tools – Extension Pack“. 

 

App generieren

Zuallererst wird eine leere SAP Fiori-Applikation erstellt, die im Verlauf des Tutorials zu einem Plugin umgewandelt wird.

Über die Command-Palette (Steuerung + Umschalt + P) wird durch Eingabe von „Open Application Generator“ ein Template-Wizard gestartet, mit dem Apps generiert werden können.

Das Template „Basic“ wird ausgewählt, um eine leere App zu erstellen.

Für die „Data Source“ wird „None“ ausgewählt, da keine Daten direkt aus unserem System bezogen werden.

Ein beliebiger Name kann für die View eingegeben werden, da wir diese nicht benötigen werden.

In den „Project Attributes“ werden ein passender „Module name“ und „Application namespace“ ausgewählt. Der „Project folder path“, in dem unsere Dateien abgelegt werden, kann nach Belieben festgelegt werden. Abschließend wird auf „Finish“ geklickt, um die App zu generieren.

Manifest.json

Nach der Generierung der App werden im „Manifest.json“, das sich im Ordner „webapp“ befindet, einige Konfigurationen vorgenommen.

Zuerst wird das Feld „type“ im „sap.app“ Objekt auf „component“ geändert.

 "type": "component", 

Des Weiteren wird das „crossNavigation“-Objekt innerhalb von „sap.app“ eingefügt.

"crossNavigation": {
 "inbounds": {
 "Shell-plugin": {
 "signature": {
 "parameters": {},
 "additionalParameters": "allowed"
 },
 "hideLauncher": true,
 "semanticObject": "Shell",
 "action": "plugin"
 }
 }
 }

Zuletzt wird auf derselben Ebene wie „sap.app“ ein „sap.flp“-Objekt hinzugefügt.

 "sap.flp": {
 "type": "plugin"
 },

Component.js

Nun wird in der Component.js die Logik programmiert, die dafür sorgt, dass die Systeminformationen im Fiori Launchpad angezeigt werden.

Zuerst wird die Methode „init“ implementiert. Diese wird automatisch und einmalig aufgerufen, wenn die App bzw. das Launchpad gestartet wird. Nachdem die „Base Component“ und das Routing initialisiert wurden, wird ein Promise in der Variable „rendererPromise“ gespeichert. Der Renderer, den wir aus diesem Promise erhalten, wird am Ende genutzt, um die Informationen in der App darzustellen. Die Informationen zum System, Client und Benutzernamen werden aus der „SAP Shell“ bezogen, in einem String zusammengeführt und über den Renderer als „Header Title“ gesetzt.

/**
 * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
 * @public
 * @override
 */
 init: function () {
 // call the base component's init function
 UIComponent.prototype.init.apply(this, arguments);
 // enable routing
 this.getRouter().initialize();
 // set the device model
 this.setModel(models.createDeviceModel(), "device");
 let rendererPromise = this._getRenderer();
 rendererPromise.then(function (oRenderer) {
 let metas = document.getElementsByTagName("meta");
 let sTitle;
 for (let meta of metas) {
 if(meta.name === "sap.ushellConfig.serverSideConfig.1") {
 let oInfos = JSON.parse(meta.content).startupConfig;
 sTitle = oInfos.system + "/" + oInfos.client + "/" + sap.ushell.Container.getUser().getFullName();
 }
 }
 if(sTitle !== undefined) { 
 oRenderer.setHeaderTitle(sTitle);
 } else {
 throw new Error("Couldn't get system infos!");
 }
 });
 },

Die Funktion „_getRenderer“ wird von der „init“-Funktion genutzt, um den Renderer aus dem Shell-Container abzurufen.

_getRenderer: function() {
 let that = this,
 oDeferred = new jQuery.Deferred(),
 oRenderer; 
 that._oShellContainer = jQuery.sap.getObject("sap.ushell.Container");
 if (!that._oShellContainer) {
 oDeffered.reject("Illegal state: shell container not available: this component must be executed in a unified shell runtime context.");
 } else {
 oRenderer = that._oShellContainer.getRenderer();
 if(oRenderer) {
 oDeferred.resolve(oRenderer);
 } else {
 // renderer not initialized yet, listen to rendererCreated event
 that._onRendererCreated = function (oEvent) {
 oRenderer = oEvent.getParameter("renderer");
 if (oRenderer) {
 oDeferred.resolve(oRenderer);
 } else {
 oDeferred.reject("Illegal state: shell renderer not available after receiving 'rendererLoaded' event.");
 }
 }
 that._oShellContainer.attachRendererCreatedEvent(that._onRendererCreated);
 }
 } 
 return oDeferred.promise();
 }

Deployment

Um das Plugin zu testen, wird das Projekt auf das SAP-System deployed.

Um die Konsole zu öffnen, klickt man mit der rechten Maustaste auf den Ordner „flpplugin“, öffnet das Kontextmenü und wählt „Open in integrated Terminal“.

Im nächsten Schritt wird eine ‚Deployment Config‘ mit dem Befehl ’npm run deploy-config‘ erstellt. Dabei wird als Ziel ‚ABAP‘ ausgewählt und anschließend das System und der Mandant angegeben. Dazu werden das ABAP-Repository sowie eine geeignete Beschreibung für den Deploy genannt. Abschließend werden das Paket und der Transportauftrag spezifiziert.

Das Deployment wird durch Ausführen des Befehls „npm run deploy“ gestartet. Bei der Frage „Start deployment (Y/n)?“ wird durch Eingabe von „y“ das Deployment begonnen.

In der Transaktion SE80 kann das bereitgestellte Plugin im zuvor angegebenen Paket gefunden werden.

Plugin aktivieren und testen

Im letzten Schritt dieses Leitfadens wird das Plugin im SAP-System aktiviert und anschließend getestet.

 

Über das SAP GUI gelangen wir zur Transaktion „/UI2/FLP_CONF_DEF“. Hier wird, in der Dialogstruktur, auf „Launchpad-Plug-Ins definieren“ gedrückt und „Neue Einträge“ gedrückt, um das Plugin zu definieren.

Im ersten Feld wird eine eindeutige ID vergeben. Anschließend wird eine Beschreibung für das Plugin sowie die entsprechende UI5-Komponenten-ID eingetragen, die im Manifest.json zu finden ist. Im letzten Feld wird eine URL eingetragen, die mit „/sap/bc/ui5_ui5/sap/“ beginnen muss.

Nun kann über das Diskettensymbol (Umschalt + S) die Definition gespeichert werden. Im daraufhin erscheinenden Fenster sollte das entsprechende Paket bereits vorausgefüllt sein. Durch einen Klick auf das grüne Häkchen wird die Speicherung abgeschlossen.

Anschließend wechselt man zur Transaktion /UI2/FLP_SYS_CONF, klickt auf den Ordner „Launchpad Plug-Ins“ und drückt den Button „Neue Einträge“.

In der Liste wird in der linken Spalte die zuvor definierte ID eingetragen und in der rechten Spalte die Option „aktiv“ ausgewählt. Anschließend wird erneut gespeichert.

Um das Plugin zu testen, startet man das Fiori Launchpad mit der Transaktion /UI2/FLP. Nach dem Öffnen des neuen Browserfensters meldet man sich mit dem eigenen SAP-Benutzerkonto an.

Der zuvor in der Component.js definierte String wird nun im Launchpad angezeigt.

Fazit

Mit diesen Schritten und Konfigurationen ist es möglich, ein SAP Fiori Launchpad Plugin zu erstellen, zu konfigurieren und erfolgreich in das System zu integrieren. Die Schaffung individueller Erweiterungen für das Fiori Launchpad ermöglicht eine maßgeschneiderte Benutzererfahrung und bietet vielfältige Möglichkeiten, um die Arbeitsabläufe in der SAP-Umgebung zu optimieren. Durch das Verständnis dieser Prozesse und die Anwendung dieser Anleitungen können Sie die Funktionalität des Fiori Launchpads nach Ihren Anforderungen anpassen und so eine effiziente und benutzerfreundliche Arbeitsumgebung schaffen.

Optimierung der SAPUI5-Code-Dokumentation durch JSDoc

In umfangreichen SAPUI5-Projekten kann das dynamische Verhalten von JavaScript in den Controllern zu Herausforderungen bezüglich Lesbarkeit und Wartbarkeit führen. Durch die Nutzung von JSDoc, einem standardisierten Dokumentationstool, wird diesem Problem entgegengewirkt.

Was ist JSDoc?

JSDoc ist ein Hilfsmittel in der JavaScript-Entwicklung, das dazu dient, Code durch spezielle Kommentare zu dokumentieren. Es ermöglicht Entwicklern, Funktionen, Klassen und Variablen klar zu beschreiben und automatisch gut strukturierte Dokumentationsseiten zu generieren.

Welche Vorteile bietet JSDoc?

Die Verwendung von JSDoc in einem SAPUI5-Projekt bietet einige Vorteile, unter anderem: 

  • Lesbarkeit: JSDoc verbessert die Lesbarkeit von JavaScript-Code, indem es Entwicklern ermöglicht, Funktionen, Klassen und Variablen mit Kommentaren zu dokumentieren.
  • Typsicherheit: Durch das Hinzufügen von Typinformationen in JSDoc-Kommentaren wird die Sicherstellung von Typkorrektheit unterstützt und die Fehlererkennung während der Entwicklung erleichtert.
  • Automatische Generierung: JSDoc ermöglicht die automatische Generierung von gut strukturierten Dokumentationsseiten, die Parameter, Rückgabetypen etc. übersichtlich darstellen.

Installation von JSDoc und Generierung der Code Dokumentation

Um JSDoc über die Konsole zu installieren, kann npm (Node Package Manager) verwendet werden. Folgender Konsolenbefehl dient zur Installation von JSDoc:

npm install jsdoc

Zum Erstellen des Dokumentations-Files kann auf zwei unterschiedliche Varianten zurückgegriffen werden. Es ist möglich, mithilfe des Konsolenbefehls jsdoc die Standardeinstellungen zu verwenden. Nach Eingabe des Befehls wird die Dokumentation automatisch erstellt.

jsdoc webapp/controller

Die zweite Möglichkeit wäre eine Konfigurationsdatei zu benutzen. Diese ermöglicht es Entwicklern, die JSDoc-Ausgabe an die Anforderungen des Projekts anzupassen

Konfigurationsdatei anlegen

Die Konfigurationsdatei befindet sich üblicherweise im Hauptverzeichnis der UI5-App.

{
 "source": {
 "include": ["webapp/controller"],
 "includePattern": ".js$"
 },
 "plugins": ["plugins/markdown"],
 "templates": {
 "recurse": true,
 "monospaceLinks": true
 },
 "opts": {
 "recurse": true,
 "destination": "./docs/"
 }
}

Nach Anlegen der Datei muss dementsprechend die package.json Datei im selbigen Projekt erweitert werden.

"scripts": {
 "doc": "jsdoc -c jsdoc.json"
 ...
 },

Im Anschluss kann nun folgender Konsolenbefehl benutzt werden

npm run doc

Wichtig zu Beachten hierbei ist, dass beide Commands nach Änderungen im Code immer neu ausgeführt werden müssen um eine neue Dokumenation zu erstellen. 

Preview

Nach Ausführung des entsprechenden Befehls zur Dokumentationserstellung wird im Hauptverzeichnis ein Ordner erstellt. Standardmäßig lautet der Ordnername out, kann jedoch mithilfe der Konfigurationsdatei beliebig verändert werden. Dieser Folder enthält die gesamte Dokumentation, einschließlich aller generierten HTML-Dateien, die im Browser eingesehen werden können.

Code-Dokumentation

Wie bereits erwähnt, startet ein JSDoc-Kommentar immer mit /**. Es ist wichtig zu beachten, dass genau zwei * eingefügt werden müssen. Andernfalls wird die Syntax nicht erkannt, und das beschriebene Element wird nicht in die generierte Dokumentation aufgenommen.

Aufbau von JSDoc

Der allgemeine Aufbau eines JSDoc Kommentars besteht aus einer Beschreibung und Block Tags

/**
 *Kommentar
 *@block-tag
 */
funktionsName: function(parameter){
 ...
}

Welche Block Tags gibt es?

Auf der offiziellen JSDoc-Website findet sich eine umfassende Dokumentation zu Block Tags. Die SAP hat jedoch in ihren SAPUI5-Richtlinien bezüglich JSDoc das Spektrum der zulässigen Block Tags etwas begrenzt.

JSDoc in UI5 implementieren

Die nachfolgenden Beispiele veranschaulichen eine konkrete Implementierung von JSDoc in SAPUI5.

Dokumentation von Klassen

Gemäß den SAP Design Guidelines sollten Klassen immer die folgenden Block-Tags enthalten:

  • @class: Fügt der Kategorie „Classes“ in der API ein Element hinzu.
  • @extends: Gibt an, ob und von welcher Klasse geerbt wird.
  • @author: Verantwortliche(r) Autor(in).
  • @since: Version, in der die Klasse erstellt wurde.
sap.ui.define([
 "at/clouddna/controller/BaseController",
 "sap/m/MessageBox",
 "sap/ui/model/json/JSONModel",
 "sap/ui/core/Fragment",
 "sap/ui/core/Item"
],
 function (BaseController, MessageBox, JSONModel, Fragment, Item) {
 "use strict";
 /**
 * This class manages a Customer
 * 
 * Detailed description of the class
 * @class Customer
 * @extends BaseController
 * @author Example Author
 * @since 1.96.0
 */
 return BaseController.extend("at.clouddna.training.controller.Customer", {
 ...
 });

Dokumentation von Funktionen und Parametern

Folgende Block-Tags sollten laut SAP Design Guidelines immer für die Beschreibung von Funktionen und Parametern vorhanden sein:

  • @public/@protected/@private: Gibt die Sichtbarkeit der Methoden in der API an. Private-Methoden werden NICHT in der API angezeigt.
  • @param: Gibt den Typen des Parameters an.
  • @returns: Gibt den Return-Type an.
/**
 * Creates a Path where Documents can be uploaded and returns it
 * @public
 * @param {string} sDocId - Document ID
 * @param {string} sCustomerId - Customer ID
 * @returns {string}
 */
 formatUrl: function(sDocId, sCustomerId){
 let sPath = this.getView().getModel().createKey("/CustomerDocumentSet", {
 DocId: sDocId,
 CustomerId: sCustomerId
 });
 return this.getView().getModel().sServiceUrl + sPath + "/$value";
 },
/**
 * Refreshs the Model
 * @public
 */
 onUploadCompleted: function(){
 this.getView().getModel().refresh(true);
 },
/**
 * Removes an Item from the UploadSet
 * @param {object} oEvent - Event object
 * @public 
 */
 onRemovePressed: function(oEvent){
 oEvent.preventDefault();
 let sPath = oEvent.getSource().getBindingContext().getPath();
 this.getView().getModel().remove(sPath);
 }

Fazit

In SAPUI5 ist die Nutzung von JSDoc ein echter Gamechanger. Durch die Dokumentation von Klassen und Methoden nach den SAP Design Guidelines wird nicht nur der Code verständlicher, sondern auch die Zusammenarbeit im Team deutlich verbessert. Die Verwendung von Block-Tags wie @public oder @private wird die Sichtbarkeit gesteuert, und das Ganze trägt dazu bei, dass SAPUI5 Projekte nicht nur effizienter, sondern auch leichter wartbar sind. JSDoc ist sozusagen der zuverlässige Begleiter für einen gut strukturierten und transparenten SAPUI5-Code.

Erweiterte Datenmanipulation in TypeScript: Nutzen Sie Map, Reduce, Filter und mehr

TypeScript bietet JavaScript-Entwicklern nicht nur ein typsicheres Umfeld, sondern auch die Möglichkeit, mit modernen funktionalen Programmierkonzepten zu arbeiten. Die Methoden map, reduce und filter sind mächtige Werkzeuge zur Verarbeitung und Transformation von Datenstrukturen, insbesondere von Arrays. In diesem Artikel erkunden wir, wie diese Funktionen in TypeScript eingesetzt werden können, um Code zu optimieren und Daten effizient zu manipulieren.

Map: Transformation von Arrays

Die map-Methode erstellt ein neues Array, indem sie eine Funktion auf jedes Element eines anderen Arrays anwendet. In TypeScript könnt ihr den Typ der Elemente des neuen Arrays explizit angeben, was zu einem sauberen und vorhersagbaren Code führt.

Beispiel:

const numbers: number[] = [1, 2, 3, 4, 5];
const squaredNumbers: number[] = numbers.map(num => num * num);
console.log(squaredNumbers); // Ausgabe: [1, 4, 9, 16, 25] 

Reduce: Akkumulation von Werten

reduce ist eine mächtige Methode, die ein Array nimmt und es auf einen einzelnen Wert reduziert. Dies kann der Summe aller Elemente, der Zusammenführung von Strings oder der Erstellung eines einzelnen Objekts aus einer Array von Objekten sein. TypeScript ermöglicht es, den Typ des Akkumulators und des Endwertes genau zu bestimmen.

Beispiel:

const numbers: number[] = [1, 2, 3, 4, 5];
const sum: number = numbers.reduce((acc: number, current: number) => acc + current, 0);
console.log(sum); // Ausgabe: 15 

Filter: Selektion von Array-Elementen

Mit filter könnt ihr ein neues Array erstellen, das nur die Elemente enthält, die eine bestimmte Bedingung erfüllen. Die Verwendung von filter in TypeScript sorgt dafür, dass das resultierende Array denselben Typ wie das ursprüngliche Array hat.

Beispiel:

const numbers: number[] = [1, 2, 3, 4, 5];
const evenNumbers: number[] = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Ausgabe: [2, 4] 

Kombinieren von Map, Reduce und Filter

Diese Methoden können kombiniert werden, um komplexe Datenmanipulationen in einer klaren und funktionalen Weise durchzuführen.

Beispiel:

const products: {id: number, price: number}[] = [
 {id: 1, price: 100},
 {id: 2, price: 200},
 {id: 3, price: 300}
];
// Gesamtpreis der Produkte mit einer ID größer als 1
const totalPrice: number = products
 .filter(product => product.id > 1)
 .reduce((acc, product) => acc + product.price, 0);
console.log(totalPrice); // Ausgabe: 500 

Fazit

Die Methoden map, reduce und filter sind essentiell für die Arbeit mit Arrays in TypeScript. Sie ermöglichen es, Operationen klar und effizient auszudrücken, ohne die Notwendigkeit für komplexe Schleifen und bedingte Anweisungen. Die zusätzliche Typsicherheit in TypeScript hilft dabei, Fehler zu vermeiden und macht den Code leichter wartbar und lesbar. Durch das Erlernen und Anwenden dieser Methoden könnt ihr eure Fähigkeiten in der funktionalen Programmierung stärken und eure TypeScript-Projekte auf die nächste Stufe bringen.

Asynchrone Meisterklasse: Effizientes Arbeiten mit Promises in TypeScript

Wenn es um asynchrone Programmierung in TypeScript geht, sind Promises ein unverzichtbares Feature, das nicht nur die Lesbarkeit des Codes verbessert, sondern auch dazu beiträgt, Typisierungsfehler zu vermeiden. TypeScript erweitert die Funktionalität von JavaScript-Promises um eine starke Typisierung, die Entwicklern eine noch größere Kontrolle über asynchrone Prozesse gibt. In diesem Artikel beleuchten wir, wie Promises in TypeScript funktionieren und wie ihr sie optimal nutzen könnt.

Was sind Promises in TypeScript?

Ein Promise in TypeScript ist genauso wie in JavaScript ein Objekt, das für einen zukünftigen Wert steht, der nach dem Abschluss einer asynchronen Operation zurückgegeben oder wegen eines Fehlers nicht zurückgegeben wird. Der große Unterschied in TypeScript ist, dass ihr den erwarteten Rückgabetyp des Promises spezifizieren könnt:

const fetchData: Promise<string> = new Promise((resolve, reject) => {
 // Asynchrone Operation hier
 if (/* operation erfolgreich */) {
 resolve("Daten erfolgreich geladen.");
 } else {
 reject(new Error("Fehler beim Laden der Daten."));
 }
}); 

Typisierte Antwort mit Promises

TypeScript ermöglicht es euch, den Typ der Antwort zu deklarieren, den ihr von einem Promise erwartet, was zu einer sichereren Entwicklungsumgebung beiträgt:

fetch('https://api.example.com/data')
 .then(response => response.json() as Promise<MyDataType>)
 .then(data => {
 console.log(data);
 })
 .catch(error => {
 console.error(error);
 }); 

Asynchrone Funktionen und Await

TypeScript unterstützt auch async/await, ein Feature, das das Arbeiten mit Promises noch einfacher macht. Durch die Kombination von async/await mit Typisierung könnt ihr die erwarteten Rückgabetypen klar definieren:
async function fetchData(): Promise<MyDataType> {
 try {
 const response = await fetch('https://api.example.com/data');
 const data: MyDataType = await response.json();
 return data; // Automatische Rückgabe eines Promises vom Typ MyDataType
 } catch (error) {
 throw new Error(error);
 }
} 

Fehlerbehandlung mit Try/Catch

Die Fehlerbehandlung in TypeScript kann durch das traditionelle try/catch-Konzept in Kombination mit asynchronen Funktionen durchgeführt werden, wobei die Fehler als typisierte Objekte behandelt werden können:
async function fetchDataWithErrorHandling(): Promise<MyDataType> {
 try {
 const response = await fetch('https://api.example.com/data');
 if (!response.ok) {
 throw new Error(`HTTP error! status: ${response.status}`);
 }
 const data: MyDataType = await response.json();
 return data;
 } catch (error) {
 console.error('Fetch error: ', error.message);
 throw error; // Weiterwerfen des Fehlers, falls benötigt
 }
} 

Zusammenführung mehrerer Promises

TypeScript bietet Promise.all an, das euch erlaubt, auf mehrere Promises zu warten und deren Ergebnisse in einem stark typisierten Array zu erhalten:
Promise.all([
 fetchDataWithErrorHandling(),
 fetchDataWithErrorHandling()
]).then((results: MyDataType[]) => {
 // Verarbeitung der Ergebnisse, die jetzt als Array von MyDataType vorliegen
}).catch(error => {
 // Fehlerbehandlung
}); 

Fazit

Promises und asynchrone Funktionen in TypeScript bieten eine starke und sichere Grundlage für die Handhabung von asynchronen Operationen. Mit der Typisierungsfähigkeit von TypeScript könnt ihr sicherstellen, dass eure Funktionen genau das zurückgeben, was sie sollen, und dadurch die Zuverlässigkeit und Lesbarkeit eures Codes erheblich verbessern. Das Verständnis und die korrekte Anwendung dieser Konzepte sind entscheidend für die Entwicklung moderner und robuster Webanwendungen.

JavaScript Promises meistern: Ihr Leitfaden für asynchrone Programmierung

In der Welt des modernen Web-Developments sind asynchrone Operationen unumgänglich. Ob es darum geht, Daten von einem Server abzurufen, eine Datei zu lesen oder einfach eine zeitverzögerte Aufgabe auszuführen – Promises sind das Herzstück der asynchronen Programmierung in JavaScript. In diesem Artikel erforschen wir, was Promises sind, wie sie funktionieren und wie man sie effektiv einsetzt, um sauberen und wartbaren Code zu schreiben.

Was ist ein Promise?

Ein Promise ist ein Objekt, das die Fertigstellung oder das Scheitern einer asynchronen Operation repräsentiert. Es ist ein Versprechen, dass zu einem späteren Zeitpunkt ein Wert vorhanden sein wird. Promises haben drei Zustände:

  • Pending (ausstehend): Die endgültige Aktion wurde noch nicht abgeschlossen.
  • Fulfilled (erfüllt): Die Aktion wurde abgeschlossen und das Promise hat einen Wert.
  • Rejected (abgelehnt): Die Aktion konnte nicht abgeschlossen werden und es ist ein Fehler aufgetreten.

Die Grundlagen von Promises

Ein einfaches Beispiel für die Erstellung eines Promises sieht so aus:

let dataPromise = new Promise((resolve, reject) => {
 // Asynchrone Operation hier
 if (/* operation erfolgreich */) {
 resolve(data); // Wert bei Erfolg
 } else {
 reject('Fehlermeldung'); // Grund des Scheiterns
 }
});
Sobald das Promise abgeschlossen ist, könnt ihr .then() für den Erfolgsfall oder .catch() für den Fehlerfall verwenden:
dataPromise
 .then(data => {
 console.log(data);
 })
 .catch(error => {
 console.error(error);
 });

Promises in der Praxis

Stellen wir uns vor, wir müssen Daten von einem Webserver abrufen. Hier kommt fetch(), eine Methode, die ein Promise zurückgibt, ins Spiel:
fetch('https://api.example.com/data')
 .then(response => response.json())
 .then(data => {
 console.log('Daten erhalten:', data);
 })
 .catch(error => {
 console.error('Fehler beim Abrufen der Daten:', error);
 });

Fehlerbehandlung

Ein entscheidender Vorteil von Promises ist die vereinfachte Fehlerbehandlung. Ihr könnt .catch() am Ende eurer Promise-Kette hinzufügen, um jegliche Fehler zu fangen, die in der Kette aufgetreten sind.

Promises und Asynchronität

Promises sind eng mit asynchronen Funktionen verbunden. Eine async Funktion ermöglicht es euch, asynchronen Code zu schreiben, der sich wie synchroner Code liest:
async function fetchData() {
 try {
 let response = await fetch('https://api.example.com/data');
 let data = await response.json();
 console.log(data);
 } catch (error) {
 console.error(error);
 }
}

Das Zusammenspiel von Promises

Manchmal müsst ihr auf mehrere asynchrone Vorgänge warten. Promise.all() ist eine mächtige Methode, die ein Array von Promises entgegennimmt und ein neues Promise zurückgibt, das erst erfüllt wird, wenn alle einzelnen Promises erfüllt sind:
Promise.all([fetch('/data1'), fetch('/data2')])
 .then(responses => {
 // Beide Promises wurden erfüllt
 })
 .catch(error => {
 // Ein oder mehrere Promises wurden abgelehnt
 });

Fazit

Promises sind ein mächtiges Werkzeug in JavaScript, das euch die Handhabung asynchroner Operationen erleichtert. Durch die Verwendung von Promises könnt ihr komplexen Code vermeiden, der durch Callback-Hell entsteht, und stattdessen klarere und wartbare Code-Strukturen erstellen. Mit Promises könnt ihr die Asynchronität in eurem Code elegant und effektiv meistern.