Java­script Pro­mi­se - Ver­spre­chen auf Erledigung

Java­script Pro­mi­ses erleich­tern die Pro­gram­mie­rung von Funk­tio­nen zur Behand­lung von asyn­chro­nen Ereignissen. 

Tra­di­tio­nell wur­den einer Funk­ti­on Refe­ren­zen auf Call­back-Funk­tio­nen mit­ge­ge­ben, die nach Erfül­lung oder Abbruch auf­zu­ru­fen sind. Der Auf­ruf die­ser Call­backs muss­te dann expli­zit in der Funk­ti­on pro­gram­miert 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 Ein­satz eines Pro­mi­se kann man die­se Funk­ti­on und den Auf­ruf ver­ein­fa­chen und standardisieren:

function myFunction(arguments) {
  return new Promise((resolve, reject)=>{
    # ... async code ...
    if (success) {
      resolve('my result');
    }
  });
}

myFunction(arguments).then(successCallback, failureCallback)

Die Funk­ti­on myFunction gibt ein Promise Objekt zurück, an das die Behand­lungs­rou­ti­nen für erfolg­rei­che Abar­bei­tung (resolve) und/oder Abbruch (reject) über­ge­ben wer­den. Die­ses Objekt bleibt im Sta­tus „pen­ding”, bis es nach Abar­bei­tung des asyn­chro­nen Codes mit resolve() oder reject() been­det und auto­ma­tisch die ent­spre­chen­den Behand­lungs­rou­ti­nen auf­ge­ru­fen werden.

Ver­ket­tung

Sind asyn­chro­ne Ope­ra­tio­nen von­ein­an­der abhän­gig, so dass die nächs­te Funk­ti­on erst star­ten kann wenn die vor­he­ri­ge erle­digt ist, kann man Promises auch ein­fach ver­ket­ten. Das ist dadurch mög­lich, dass die .then() Funk­ti­on auch wie­der ein Promise Objekt zurückgibt:

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);

Das zwei­te Promise Objekt (promise2) reprä­sen­tiert jetzt nicht nur die Abar­bei­tung der Funk­ti­on doSomething(), son­dern auch die über­ge­be­nen Behand­lungs­rou­ti­nen. Das kön­nen aber auch wie­der asyn­chro­ne Funk­tio­nen sein, die ein Promise Objekt zurück­ge­ben. Ist das der Fall, wer­den die­se Funk­tio­nen in einer Ket­te abge­ar­bei­tet, wobei die fol­gen­de Funk­ti­on immer auf die Been­di­gung (also den Auf­ruf der resolve bzw. reject Funk­ti­on) der vor­her­ge­hen­den 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 Funk­ti­on catch(failureCallback) ist ein Ali­as für then(null, failureCallback). Wenn Die Feh­ler­be­hand­lungs­rou­ti­ne für alle Funk­tio­nen die Glei­che ist, kann sie mit catch ans Ende der Ket­te gehängt wer­den und gilt dann für alle Funk­tio­nen gleichermaßen.

Es ist wich­tig, dass die mit .then() über­ge­be­nen Funk­tio­nen immer ein Promise Objekt zurück­ge­ben. Ansons­ten bleibt das Pro­mi­se der vor­her­ge­hen­den Funk­ti­on unge­löst (floa­ting).

Die glei­che Funk­ti­on wie die Ket­te von .then() Funk­tio­nen erfüllt übri­gens eine Rei­he von await Anwei­sun­gen in eine async Funk­ti­on, was mög­li­cher­wei­se über­sicht­li­cher 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();

Kom­bi­na­tio­nen

Promises kön­nen mit­ein­an­der kom­bi­niert wer­den, so dass eine Fol­ge­funk­ti­on erst aus­ge­führt wird, wenn das Kom­bi­na­ti­ons­ziel erfüllt ist. Die Funk­tio­nen im Promise lau­fen dabei par­al­lel ab und war­ten nicht auf­ein­an­der. Es exis­tie­ren vier unter­schied­li­che Vari­an­ten für die Start­be­din­gung der .then Funktion:

  • Promise.all((func2, func2, ...).then((result1, result2, result3)=>{ ... use results ... }
    Die .then Funk­ti­on Wird aus­ge­führt, wenn alle Promises ent­we­der resolved sind oder ein rejected auf­tritt. Der ers­te reject bricht alle ande­ren Funk­tio­nen ab.
  • Promis.allSettled
    Wie oben, aber wird nicht beim ers­ten reject abge­bro­chen, son­dern erst aus­ge­führt, wenn alle Funk­tio­nen ent­we­der resolved oder rejected sind.
  • Promise.any
    Wie oben, aber die Promise wird erfüllt, wenn die ers­te der ange­ge­be­nen Funk­tio­nen resolve auf­ruft oder wenn alle Funk­tio­nen rejected sind. Der Ergeb­nis­wert ist ent­we­der das Ergeb­nis der ers­ten erfolg­rei­chen Funk­ti­on oder ein Array der reject-Ergebnisse.
  • Promise.race(promise1, promise2, ...).then((result)=>{ ... use results ... }
    Gibt ein Promise Objekt zurück, das erfüllt wird, wenn eines der über­ge­be­nen Promises erfüllt (resolve) oder abge­bro­chen (reject) wird; das Ergeb­nis ist das des ers­ten been­de­ten Promise.

Quel­len:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

zwei × 5 =