Javascript Promises erleichtern die Programmierung von Funktionen zur Behandlung von asynchronen Ereignissen.
Traditionell wurden einer Funktion Referenzen auf Callback-Funktionen mitgegeben, die nach Erfüllung oder Abbruch aufzurufen sind. Der Aufruf dieser Callbacks musste dann explizit in der Funktion programmiert werden:
function successCallback(result){
console.log( 'Success: ' + result );
}
function failureCallback(error){
console.log( 'Failure: ' + error );
}
function myFunction(arguments, successCallback, failureCallback) {
# ... async code ...
if (success && typeof successCallback === 'function') {
successCallback('my result');
}
}
myFunction((arguments, successCallback, failureCallback);
Mit dem Einsatz eines Promise kann man diese Funktion und den Aufruf vereinfachen und standardisieren:
function myFunction(arguments) {
return new Promise((resolve, reject)=>{
# ... async code ...
if (success) {
resolve('my result');
}
});
}
myFunction(arguments).then(successCallback, failureCallback)
Die Funktion myFunction gibt ein Promise Objekt zurück, an das die Behandlungsroutinen für erfolgreiche Abarbeitung (resolve) und/oder Abbruch (reject) übergeben werden. Dieses Objekt bleibt im Status „pending”, bis es nach Abarbeitung des asynchronen Codes mit resolve() oder reject() beendet und automatisch die entsprechenden Behandlungsroutinen aufgerufen werden.
Verkettung
Sind asynchrone Operationen voneinander abhängig, so dass die nächste Funktion erst starten kann wenn die vorherige erledigt ist, kann man Promises auch einfach verketten. Das ist dadurch möglich, dass die .then() Funktion auch wieder ein Promise Objekt zurückgibt:
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
Das zweite Promise Objekt (promise2) repräsentiert jetzt nicht nur die Abarbeitung der Funktion doSomething(), sondern auch die übergebenen Behandlungsroutinen. Das können aber auch wieder asynchrone Funktionen sein, die ein Promise Objekt zurückgeben. Ist das der Fall, werden diese Funktionen in einer Kette abgearbeitet, wobei die folgende Funktion immer auf die Beendigung (also den Aufruf der resolve bzw. reject Funktion) der vorhergehenden wartet.
function doSomething() {
return new Promise((resolve) => {
console.log("doing something...";
setTimeout(() => {
console.log("Did something");
resolve("my result");
}, 200);
});
}
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
Die .catch Funktion catch(failureCallback) ist ein Alias für then(null, failureCallback). Wenn Die Fehlerbehandlungsroutine für alle Funktionen die Gleiche ist, kann sie mit catch ans Ende der Kette gehängt werden und gilt dann für alle Funktionen gleichermaßen.
Es ist wichtig, dass die mit .then() übergebenen Funktionen immer ein Promise Objekt zurückgeben. Ansonsten bleibt das Promise der vorhergehenden Funktion ungelöst (floating).
Die gleiche Funktion wie die Kette von .then() Funktionen erfüllt übrigens eine Reihe von await Anweisungen in eine async Funktion, was möglicherweise übersichtlicher ist.
async function doIt(){
try {
const result_1 = await doSomething();
const result_2 = await doSomethingElse(result_1);
const finalResult = await doThirdThing(Result_2);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
}
doIt();
Kombinationen
Promises können miteinander kombiniert werden, so dass eine Folgefunktion erst ausgeführt wird, wenn das Kombinationsziel erfüllt ist. Die Funktionen im Promise laufen dabei parallel ab und warten nicht aufeinander. Es existieren vier unterschiedliche Varianten für die Startbedingung der .then Funktion:
Promise.all((func2, func2, ...).then((result1, result2, result3)=>{ ... use results ... }
Die.thenFunktion Wird ausgeführt, wenn allePromisesentwederresolvedsind oder einrejectedauftritt. Der ersterejectbricht alle anderen Funktionen ab.Promis.allSettled
Wie oben, aber wird nicht beim erstenrejectabgebrochen, sondern erst ausgeführt, wenn alle Funktionen entwederresolvedoderrejectedsind.Promise.any
Wie oben, aber diePromisewird erfüllt, wenn die erste der angegebenen Funktionenresolveaufruft oder wenn alle Funktionenrejectedsind. Der Ergebniswert ist entweder das Ergebnis der ersten erfolgreichen Funktion oder ein Array der reject-Ergebnisse.Promise.race(promise1, promise2, ...).then((result)=>{ ... use results ... }
Gibt einPromiseObjekt zurück, das erfüllt wird, wenn eines der übergebenenPromiseserfüllt (resolve) oder abgebrochen (reject) wird; das Ergebnis ist das des ersten beendetenPromise.
Quellen: