Blog

Versprechen und Entwurfsmuster in AngularJS

Freek Wielstra

Aktualisiert Oktober 22, 2025
15 Minuten

Die traditionelle Art, mit asynchronen Aufgaben in Javascript umzugehen, sind Rückrufe: Rufen Sie eine Methode auf und geben Sie ihr eine Funktionsreferenz, die ausgeführt wird, sobald die Methode beendet ist.

$.get('api/gizmo/42', function(gizmo) {
  console.log(gizmo); // oder was auch immer
});

Das ist zwar ganz nett, hat aber auch einige Nachteile. Zum einen ist es schwierig, mehrere asynchrone Prozesse zu kombinieren oder zu verketten, was entweder zu einer Menge Standardcode oder zur so genannten Callback-Hölle (Verschachtelung von Callbacks und Aufrufen ineinander) führt:

$.get('api/gizmo/42', function(gizmo) {
  $.get('api/foobars/' + gizmo, function(foobar) {
  $.get('api/barbaz/' + foobar, function(bazbar) {
  doSomethingWith(gizmo, foobar, bazbar);
  }, errorCallback);
  }, errorCallback);
}, errorCallback);

Sie haben die Idee. In Javascript gibt es jedoch eine Alternative zum Umgang mit asynchronem Code: Futures, obwohl sie in Javascript oft als Promises bezeichnet werden. Das CommonJS Standardisierungskomitee hat eine Spezifikation veröffentlicht, die diese API namens Promises definiert.

Das Konzept hinter den Versprechen ist recht einfach und besteht aus zwei Komponenten:

  • Deferreds, die Einheiten von Arbeit darstellen, und
  • Promises, die Daten aus diesen Deferreds darstellen.

[caption id="attachment_12537" align="alignleft" width="480"]Quelle: https://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt1-theory-and-semantics Quelle: https://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt1-theory-and-semantics[/caption] Grundsätzlich verwenden Sie ein Deferred als Kommunikationsobjekt, um den Beginn, den Fortschritt und den Abschluss einer Arbeit zu signalisieren. Ein Promise wiederum ist ein Objekt, das von einem Deferred ausgegeben wird und Daten repräsentiert; es hat einen bestimmten Status (ausstehend, erfüllt oder abgelehnt) und Handler oder Callback-Methoden, die aufgerufen werden sollten, sobald ein Promise aufgelöst, abgelehnt oder eine Fortschrittsaktualisierung gegeben wird. Ein wichtiger Unterschied zwischen Promises und Callbacks ist, dass Sie einen Handler anhängen können , nachdem der Status des Promises auf aufgelöst geht. So können Sie Daten, die noch nicht vorhanden sind, in Ihrer Anwendung weitergeben, sie zwischenspeichern usw., so dass die Verbraucher Operationen mit den Daten durchführen können, entweder sofort oder sobald sie eintreffen. Im weiteren Verlauf dieses Artikels werden wir über Versprechen und dergleichen im Zusammenhang mit AngularJS sprechen. AngularJS stützt sich in seiner gesamten Codebasis stark auf Versprechen, sowohl im Framework als auch in dem Anwendungscode, den Sie darin schreiben. AngularJS verwendet seine eigene Implementierung der Promises-Spezifikation, den $q-Dienst, der wiederum eine leichtgewichtige Implementierung der Q-Bibliothek ist. $q implementiert alle oben beschriebenen Deferred / Promise-Methoden sowie einige in $q selbst: $q.defer(), das ein neues Deferred-Objekt erzeugt; $q.all(), mit dem Sie auf die Auflösung mehrerer Promises warten können, und die Methoden $q.when() und $q.reject(), Utility-Methoden, auf die wir später noch eingehen werden. $q.defer() gibt ein Deferred-Objekt zurück, das über die Methoden resolve(), reject() und notify() verfügt. Deferred hat eine Eigenschaft promise, nämlich das promise-Objekt, das in der Anwendung weitergereicht werden kann. Das promise-Objekt hat drei weitere Methoden:.then(), die einzige von der Promises-Spezifikation geforderte Methode, die drei Rückrufe als Argumente akzeptiert: einen für Erfolg, einen für Misserfolg und einen für Benachrichtigungen. $q fügt der Promise-Spezifikation jedoch zwei Methoden hinzu: catch(), die verwendet werden kann, um eine zentrale Funktion zu haben, die aufgerufen wird, wenn eines der Versprechen in einer Versprechenskette fehlschlägt, und finally(), eine Methode, die unabhängig vom Erfolg oder Misserfolg der Versprechen immer aufgerufen wird. Beachten Sie, dass diese Methoden nicht mit der Ausnahmebehandlung von Javascript verwechselt oder kombiniert werden dürfen: Eine Ausnahme, die innerhalb eines Versprechens ausgelöst wird, wird von catch() nicht abgefangen.

Einfaches Beispiel für ein Versprechen

Hier ist ein einfaches Beispiel für die Verwendung von $q, Deferred und Promise in einem. Ich möchte Sie darauf hinweisen, dass keines der Codebeispiele in diesem Beitrag getestet wurde. Außerdem fehlen die entsprechenden Angular-Dienste und Abhängigkeitsdefinitionen usw. Aber sie sollten als Beispiel ausreichen, um selbst damit zu experimentieren. Zunächst erstellen wir eine neue Arbeitseinheit, indem wir mit $q.defer() ein Deferred-Objekt erzeugen:

var deferred = $q.defer();

Als nächstes holen wir uns das Versprechen aus dem Deferred und fügen ihm ein Verhalten hinzu.

var promise = deferred.promise;
promise.then(function erfolg(daten) {
  console.log(data);
}, function error(msg) {
  console.error(msg);
});

Zum Schluss führen wir eine Scheinarbeit aus und zeigen an, dass wir fertig sind, indem wir den Aufschub mitteilen:

deferred.resolve('alles erledigt!');

Natürlich ist das nicht wirklich asynchron, also können wir das mit dem $timeout-Dienst von Angular vortäuschen (oder mit setTimeout von Javascript, aber ich bevorzuge $timeout in Angular-Anwendungen, damit Sie es nachahmen/testen können)

$timeout(function() {
  deferred.resolve('Alles erledigt... irgendwann');
}, 1000);

Und das Beste daran: Wir können mehrere then()s an ein einziges Versprechen anhängen und auch then()s anhängen , nachdem das Versprechen aufgelöst wurde:

var deferred = $q.defer();
var promise = deferred.promise;
// Verhalten vor dem Auflösen zuweisen
promise.then(function (data) {
  console.log('vorher:', data);
});
deferred.resolve("Oh, wir sind schon fertig.")
// Verhalten nach dem Auflösen zuweisen
promise.then(function (data) {
  console.log('after:', data);
});

Und wenn nun ein Fehler auftritt? Dann verwenden wir deferred.reject(), wodurch das zweite Argument von then() aufgerufen wird. Genau wie Rückrufe.

var deferred = $q.defer();
var promise = deferred.promise;
promise.then(function erfolg(daten) {
  console.log('Erfolg!', data);
}, function error(msg) {
  console.error('Fehlschlag!', msg);
});
deferred.reject('Wir sind gescheitert :(');

Als Alternative zur Übergabe eines zweiten Arguments an then() können Sie es mit einem catch() verketten, das aufgerufen wird, wenn in der Versprechenskette etwas schief läuft (mehr zur Verkettung später):

Versprechen
  .then(function erfolg(daten) {
  console.log(data);
  })
  .catch(function error(msg) {
  console.error(msg);
  });

Nebenbei bemerkt können Sie für längerfristige Prozesse (wie Uploads, lange Berechnungen, Batch-Operationen usw.) deferred.notify() und das dritte Argument von then() verwenden, um den Zuhörern des Versprechens ein Status-Update zu geben:

var deferred = $q.defer();
var promise = deferred.promise;
Versprechen
  .then(function erfolg(daten) {
  console.log(data);
  },
  Funktion Fehler(Fehler) {
  console.error(error);
  },
  Funktion Benachrichtigung(Benachrichtigung) {
  console.info(notification);
  }
);
var progress = 0;
var intervall = $intervall(function() {
  wenn (Fortschritt  >= 100) {
  $interval.cancel(interval);
  deferred.resolve('Alles erledigt!');
  }
  Fortschritt += 10;
  deferred.notify(progress + '%...');
}, 100)

Verkettung von Versprechen

Wir haben bereits gesehen, dass Sie mehrere Handler(then()) an ein einzelnes Versprechen anhängen können. Das Schöne an der Versprechen-API ist, dass sie die Verkettung von Handlern erlaubt:

Versprechen
  .then(doSomething)
  .then(doSomethingElse)
  .then(doSomethingMore)
  .catch(logError);

Ein einfaches Beispiel: So können Sie Ihre Funktionsaufrufe sauber in reine Einzweckfunktionen aufteilen, statt in eine einzige Funktion, die alles erledigt. Ein doppelter Bonus ist, wenn Sie diese Funktionen für mehrere Promise-ähnliche Aufgaben wiederverwenden können, so wie Sie funktionale Methoden (für Listen und dergleichen) verketten würden. Sie wird noch leistungsfähiger, wenn Sie das Ergebnis eines vorherigen asynchronen Vorgangs verwenden, um einen nächsten auszulösen. Standardmäßig wird bei einer Kette wie der obigen das zurückgegebene Objekt an das nächste then() übergeben. Beispiel:

var deferred = $q.defer();
var promise = deferred.promise;
Versprechen
  .then(function(val) {
  console.log(val);
  geben Sie 'B' zurück;
  })
  .then(function(val) {
  console.log(val);
  Rückgabe 'C'
  })
  .then(function(val) {
  console.log(val);
  });
deferred.resolve('A');

Dadurch wird Folgendes auf der Konsole ausgegeben:

A
B
C

Dies ist allerdings nur ein einfaches Beispiel. Richtig mächtig wird es, wenn Ihr then() -Callback ein anderes Versprechen zurückgibt. In diesem Fall wird das nächste then() erst ausgeführt, wenn dieses Versprechen aufgelöst wird. Dieses Muster kann z.B. für serielle HTTP-Anfragen verwendet werden (bei denen eine Anfrage vom Ergebnis einer vorherigen abhängt):

var deferred = $q.defer();
var promise = deferred.promise;
// nach einer Sekunde auflösen
$timeout(function() {
  deferred.resolve('foo');
}, 1000);
Versprechen
  .then(function(one) {
  console.log('Versprechen eins aufgelöst mit ', eins);
  var anotherDeferred = $q.defer();
  // wird nach einer weiteren Sekunde aufgelöst
  $timeout(function() {
  anotherDeferred.resolve('bar');
  }, 1000);
  return anotherDeferred.promise;
  })
  .then(function(zwei) {
  console.log('Versprechen zwei aufgelöst mit ', zwei);
  });

Zusammengefasst:

  • Promise-Ketten rufen das nächste 'then' in der Kette mit dem Rückgabewert des vorherigen 'then'-Callbacks auf (oder undefiniert, wenn es keinen gibt)
  • Wenn ein 'then'-Callback ein promise-Objekt zurückgibt, wird das nächste 'then' nur ausgeführt, wenn dieses promise aufgelöst wird.
  • Ein abschließendes 'catch' am Ende der Kette bietet einen einzigen Fehlerbehandlungspunkt für die gesamte Kette
  • Ein 'finally' am Ende der Kette wird immer ausgeführt, unabhängig davon, ob ein Versprechen aufgelöst oder abgelehnt wird, um eine Bereinigung zu erreichen.

Parallele Versprechen und 'Versprechen-ifizieren' einfacher Werte

Eine Methode, die ich in Brielfly erwähnt habe, ist $q.all(), mit der Sie parallel auf die Auflösung mehrerer Versprechen warten können, wobei ein einziger Rückruf ausgeführt wird, wenn alle Versprechen aufgelöst sind. In Angular kann diese Methode auf zwei Arten aufgerufen werden: mit einem Array oder einem Objekt. Die Array-Variante nimmt ein Array und ruft den .then() -Callback mit einem einzigen Array-Ergebnisobjekt auf, wobei die Ergebnisse der einzelnen Versprechen ihrem Index im Eingabe-Array entsprechen:

$q.all([VersprechenEins, VersprechenZwei, VersprechenDrei])
  .then(function(ergebnisse) {
  console.log(ergebnisse[0], ergebnisse[1], ergebnisse[2]);
  });

Die zweite Variante akzeptiert ein Objekt mit Versprechen und ermöglicht es Ihnen, diesen Versprechen in Ihrer Callback-Methode Namen zu geben (was sie anschaulicher macht):

$q.all({ erste: versprechenEins, zweite: versprechenZwei, dritte: versprechenDrei })
  .then(function(ergebnisse) {
  console.log(ergebnisse.erste, ergebnisse.zweite, ergebnisse.dritte);
  });

Ich würde die Array-Notation nur dann empfehlen, wenn Sie das Ergebnis stapelweise verarbeiten können, d.h. wenn Sie die Ergebnisse gleich behandeln. Die Objektschreibweise eignet sich besser für selbstdokumentierenden Code. Eine weitere Hilfsmethode ist $q.when(), die nützlich ist, wenn Sie einfach nur ein Versprechen aus einer einfachen Variablen erstellen möchten oder wenn Sie einfach nicht sicher sind, ob Sie es mit einem Versprechungsobjekt zu tun haben.

$q.when('foo')
  .then(function(bar) {
  console.log(bar);
  });
$q.when(aVersprechen)
  .then(function(baz) {
  console.log(baz);
  });
$q.when(WertOderVersprechen)
  .then(function(boz) {
  // Nun, Sie verstehen schon.
  })

$q.when() ist auch für Dinge wie das Zwischenspeichern in Diensten nützlich:

angular.module('myApp').service('MyService', function($q, MyResource) {
var cachedSomething;
this.getSomething = function() {
  if (cachedSomething) {
  return $q.when(cachedSomething);
  }
  // Beim ersten Aufruf geben Sie das Ergebnis von MyResource.get() zurück.
  // Beachten Sie, dass 'then()' verkettbar ist / ein Versprechen zurückgibt,
  // damit wir dies anstelle eines separaten Versprechensobjekts zurückgeben können
  return MeineRessource.get().$Versprechen
  .then(function(etwas) {
  cachedSomething = etwas
  });
  };
});

Und dann nennen Sie es so:

MyService.getSomething()
  .then(function(etwas) {
  console.log(etwas);
  });

Praktische Anwendungen in AngularJS

Die meisten E/A in Angular geben Promises oder Promise-kompatible ('then-able') Objekte zurück, allerdings oft mit einem Twist. Die Dokumentation von $http gibt an, dass es ein HttpPromise-Objekt zurückgibt, das ein Promise ist, aber zwei zusätzliche (Hilfs-)Methoden hat, wahrscheinlich um jQuery-Benutzer nicht zu sehr abzuschrecken. Es definiert die Methoden success() und error(), die dem ersten bzw. zweiten Argument eines then() -Callbacks entsprechen. Der Service $resource von Angular, ein Wrapper um $http für REST-Endpunkte, ist ebenfalls etwas seltsam. Die generierten Methoden(get(), save() undsoforth) akzeptieren ein zweites und drittes Argument als Erfolgs- und Fehler-Callbacks, während sie auch ein Objekt zurückgeben, das mit den angeforderten Daten gefüllt wird, wenn die Anfrage gelöst wird. Es gibt nicht direkt ein promise-Objekt zurück; stattdessen hat das von der get() -Methode einer Ressource zurückgegebene Objekt eine Eigenschaft $promise, die das zugrundeliegende promise-Objekt offenlegt. Einerseits ist es inkonsistent mit $http und der Tatsache, dass alles in Angular ein promise ist oder sein sollte, aber andererseits erlaubt es einem Entwickler, das Ergebnis von $resource.get() einfach dem $scope zuzuweisen. Früher konnte ein Entwickler dem $scope ein beliebiges Versprechen zuweisen, aber seit Angular 1.2 ist das veraltet: siehe diesen Commit, in dem es veraltet wurde. Ich persönlich mag eine konsistente API, daher verpacke ich so gut wie alle E/A in einen Service, der immer ein Versprechen-Objekt zurückgibt, aber auch, weil der Aufruf einer $Ressource oft ein wenig unübersichtlich ist. Hier ist ein zufälliges Beispiel:

angular.module('fooApp')
  .service('BarResource', function ($resource) {
  return $resource('api/bar/:id');
  })
  .service('BarService', function (BarResource) {
  this.getBar = function (id) {
  return BarResource.get({
  id: id
  }).$Versprechen;
  }
  });

  Dieses Beispiel ist etwas undurchsichtig, weil die Übergabe des id-Arguments an BarResource etwas doppelt aussieht, aber es ist sinnvoll, wenn Sie ein komplexes Objekt haben, aber einen Dienst nur mit einer ID-Eigenschaft davon aufrufen müssen. Der Vorteil dieser Vorgehensweise ist, dass Sie in Ihrem Controller wissen, dass alles, was Sie von einem Service erhalten, immer ein Promise-Objekt sein wird. Sie müssen sich nicht fragen, ob es sich um ein Promise, ein Ressourcenergebnis oder ein HttpPromise handelt, was wiederum Ihren Code konsistenter und vorhersehbarer macht - und da Javascript schwach typisiert ist und es meines Wissens noch keine IDE gibt, die Ihnen sagen kann, welchen Typ eine Methode ohne vom Entwickler hinzugefügte Annotationen zurückgibt, ist das ziemlich wichtig.

Praktisches Beispiel einer Verkettung

Ein Teil der Codebasis, an der wir derzeit arbeiten, enthält Aufrufe, die sich auf die Ergebnisse eines vorherigen Aufrufs verlassen. Promises sind dafür ideal und ermöglichen es Ihnen, einen leicht lesbaren Code zu schreiben, solange Sie Ihren Code sauber halten. Betrachten Sie das folgende Beispiel:

angular.module('WebShopApp')
  .controller('CheckoutCtrl', function($scope, $log, CustomerService, CartService, CheckoutService) {
  function berechneSummen(Warenkorb) {
  cart.total = cart.products.reduce(function(prev, current) {
  return prev.price + current.price;
  });
  Warenkorb zurückgeben;
  }
  CustomerService.getCustomer(currentCustomer)
  .then(CartService.getCart) // getCart() benötigt ein Kundenobjekt und gibt einen Warenkorb zurück
  .then(berechneSummen)
  .then(CheckoutService.createCheckout) // createCheckout() benötigt ein Warenkorb-Objekt, gibt ein Checkout-Objekt zurück
  .then(function(checkout) {
  $scope.checkout = checkout;
  })
  .catch($log.error)
  });

  Dies kombiniert das asynchrone Abrufen von Daten (Kunden, Warenkörbe, Erstellen einer Kasse) mit der synchronen Verarbeitung von Daten(calculateTotals). Die Implementierung weiß jedoch nicht, ob diese verschiedenen Dienste asynchron sind oder nicht, und muss auch nicht wissen, ob sie asynchron sind oder nicht, sondern wartet einfach darauf, dass die Methoden abgeschlossen werden, ob asynchron oder nicht. In diesem Fall könnte getCart() Daten aus dem lokalen Speicher abrufen, createCheckout() könnte eine HTTP-Anfrage durchführen, um sicherzustellen, dass alle Produkte vorrätig sind, und so weiter. Aber aus der Sicht des Verbrauchers (der die Aufrufe tätigt) spielt das keine Rolle; es funktioniert einfach. Und es ist klar ersichtlich, was es tut, solange Sie sich daran erinnern, dass das Ergebnis der vorherigen then() an die nächste übergeben wird. Und natürlich ist es selbstdokumentierend und prägnant.

Testen von Versprechen-basiertem Code

Das Testen von Versprechen ist einfach genug. Sie können entweder den harten Weg gehen und Ihren Test Mock-Objekte erstellen lassen, die eine then() -Methode bereitstellen, die direkt aufgerufen wird. Der Einfachheit halber verwende ich jedoch nur $q, um Versprechen zu erstellen - es ist eine sehr schnelle Bibliothek und Sie werden garantiert keine Feinheiten der Versprechensimplementierung übersehen. Die folgende Spezifikation versucht zu demonstrieren, wie Sie die verschiedenen oben verwendeten Dienste mocken können. Beachten Sie, dass die Spezifikation recht ausführlich und lang ist, aber ich habe noch keinen Weg gefunden, sie zu umgehen, abgesehen von der Erstellung von Utility-Methoden für die Erstellung von Versprechen (Hinweise auf eine kürzere/prägnantere Spezifikation sind willkommen).

describe('Der Checkout-Controller', function () {
  beforeEach(module('WebShopApp'));
  it('sollte etwas mit Versprechen machen', inject(function ($controller, $q, $rootScope) {
  // Mocks erstellen; in diesem Fall verwende ich Jasmine, das sich für mich bisher als Mocking-Bibliothek bewährt hat.
  var CustomerService = jasmine.createSpyObj('CustomerService', ['getCustomer']);
  var CartService = jasmine.createSpyObj('CartService', ['getCart']);
  var CheckoutService = jasmine.createSpyObj('CheckoutService', ['createCheckout']);
  var $scope = $rootScope.$new();
  var $log = jasmine.createSpyObj('$log', ['error']);
  // Erstellen Sie Deferreds für jeden der (promise-basierten) Dienste
  var customerServiceDeferred = $q.defer();
  var cartServiceDeferred = $q.defer();
  var checkoutServiceDeferred = $q.defer();
  // Lassen Sie die Mocks die Versprechen ihrer jeweiligen Deferreds zurückgeben
  CustomerService.getCustomer.andReturn(customerServiceDeferred.promise);
  CartService.getCart.andReturn(cartServiceDeferred.promise);
  CheckoutService.createCheckout.andReturn(checkoutServiceDeferred.promise);
  // Erstellen Sie den Controller; dadurch wird der erste Aufruf (getCustomer) ausgeführt,
  // und es wird halten, bis wir anfangen, Versprechen aufzulösen.
  $controller("CheckoutCtrl", {
  $scope: $scope,
  KundenService: KundenService,
  CartService: CartService,
  CheckoutService: CheckoutService
  });
  // Lösen Sie den ersten Kunden auf.
  var firstCustomer = { id: "Kunde 1" };
  customerServiceDeferred.resolve(firstCustomer);
  // ... Allerdings wird dadurch der 'then()'-Callback noch nicht aufgerufen;
  // wir müssen Angular sagen, dass es zuerst einen Zyklus ausführen soll:
  $rootScope.$apply();
  expect(CartService.getCart).toHaveBeenCalledWith(firstCustomer);
  // Auflösung des nächsten Versprechens einrichten
  var cart = { Produkte: [{ Preis: 1 }, { Preis: 2 }] }
  cartServiceDeferred.resolve(cart);
  // das nächste 'dann' anwenden
  $rootScope.$apply();
  var expectedCart = angular.copy(cart);
  cart.total = 3;
  expect(CheckoutService.createCheckout).toHaveBeenCalledWith(expectedCart);
  // Lösen Sie den Checkout-Dienst auf
  var checkout = { gesamt: 3 }; // spielt eigentlich keine Rolle
  checkoutServiceDeferred.resolve(checkout);
  // das nächste 'dann' anwenden
  $rootScope.$apply();
  expect($scope.checkout).toEqual(checkout);
  expect($log.error).not.toHaveBeenCalled();
  }));
});

  Wie Sie sehen, ist das Testen von Versprechungscode etwa zehnmal so lang wie der Code selbst. Ich weiß nicht, ob / wie man die gleiche Leistung mit weniger Code erreichen kann, aber vielleicht gibt es ja eine Bibliothek, die ich noch nicht gefunden (oder erstellt) habe. Um eine vollständige Testabdeckung zu erreichen, muss man Tests schreiben, bei denen alle drei Dienste nacheinander fehlschlagen, um sicherzustellen, dass der Fehler protokolliert wird. Auch wenn es im Code nicht deutlich sichtbar ist, hat der Code/Prozess tatsächlich viele Verzweigungen. Jedes Versprechen kann schließlich aufgelöst oder zurückgewiesen werden, wahr oder falsch sein oder verzweigen. Aber die Granularität der Tests bleibt letztendlich Ihnen überlassen. Ich hoffe, dass dieser Artikel Ihnen einen Einblick in Versprechen gibt und wie sie in jeder Angular-Anwendung verwendet werden können. Ich glaube, ich habe nur an der Oberfläche der Möglichkeiten gekratzt, sowohl in diesem Artikel als auch in den AngularJS-Projekten, die ich bisher durchgeführt habe. Für eine so einfache API und so einfache Konzepte sind die Macht und die Auswirkungen, die Promises auf die meisten Javascript-Anwendungen haben, verblüffend. In Kombination mit funktionalen Dienstprogrammen auf hoher Ebene und einer sauberen Codebasis können Sie Ihre Anwendung auf saubere, wartbare und leicht zu ändernde Weise schreiben; fügen Sie einen Handler hinzu, verschieben Sie ihn, ändern Sie die Implementierung - all diese Dinge sind einfach zu tun und zu verstehen, wenn Sie Promises unter Kontrolle haben. Vor diesem Hintergrund ist es etwas seltsam, dass Promises schon früh in der Entwicklung von NodeJS zugunsten des aktuellen Callback-Verfahrens gestrichen wurden. Ich habe mich noch nicht eingehend damit befasst, aber es scheint, dass es Leistungsprobleme gab, die nicht mit den Zielen von Node vereinbar waren. Ich denke jedoch, dass es Sinn macht, wenn Sie NodeJS als Low-Level-Bibliothek betrachten; es gibt viele Bibliotheken, die Node die höherwertige Versprechen-API hinzufügen (wie das bereits erwähnte Q). Eine weitere Anmerkung ist, dass ich diesen Beitrag mit Blick auf AngularJS geschrieben habe. Versprechen und versprechenähnliche Programmierung sind jedoch schon seit ein paar Jahren im Großvater der Javascript-Bibliotheken, jQuery, möglich; Deferreds wurden in jQuery 1.5 (Januar 2011) hinzugefügt. Nicht alle Plugins verwenden sie jedoch konsequent. Auch die Model api von Backbone.js stellt in ihren Methoden(save() usw.) Versprechen zur Verfügung, aber soweit ich weiß, funktioniert sie nicht wirklich mit den Model Events. Vielleicht irre ich mich aber auch, es ist schon eine Weile her. Ich würde auf jeden Fall empfehlen, bei der Entwicklung einer neuen Webapplikation eine auf Versprechen basierende Front-End-Anwendung anzustreben, da der Code dadurch viel sauberer wird, insbesondere in Kombination mit funktionalen Programmierparadigmen. Weitere funktionale Programmiermuster finden Sie in Reginald Braithwaites Buch Javascript Allongé, das Sie kostenlos bei LeanPub lesen können; einige davon sollten auch beim Schreiben von Promise-basiertem Code nützlich sein.

Verfasst von

Freek Wielstra

Freek is an allround developer whose major focus has been on Javascript and large front-end applications for the past couple of years, building web and mobile web applications in Backbone and AngularJS.

Contact

Let’s discuss how we can support your journey.