Blog

Erweitern von AngularJS-Diensten mit der Decorate-Methode

Freek Wielstra

Aktualisiert Oktober 22, 2025
6 Minuten

Viele große Angular-Anwendungen neigen dazu, sich stark zu wiederholen - derselbe API-Endpunkt, dieselbe Methode für den Umgang mit und die Umwandlung von Daten und so weiter. Eine Technik, mit der Sie dies zumindest abmildern können, ist die Decorate-Methode von AngularJS, mit der Sie jeden bestehenden Dienst erweitern, anpassen oder sogar vollständig ersetzen können. Wie Sie in diesem Beitrag sehen werden, können Sie damit das Framework, in dem Sie Ihre Anwendung erstellen, ändern und erweitern, was zu einer saubereren, besser lesbaren Codebasis führt, die in einem funktionaleren Stil geschrieben ist (das Was, nicht das Wie). Update 11/8 : Das Follow-up ist jetzt live, zusammen mit dem GitHub-Repository.

Eine Funktion, die bei der Entwicklung von AngularJS-Anwendungen nicht oft verwendet wird, ist der $provide-Dienst. Er ist der primäre Dienst zur Registrierung von Komponenten mit dem $injector. Normalerweise würde ein Entwickler dazu Methoden wie $provide.service() oder $provide.factory verwenden, aber dabei handelt es sich lediglich um Hilfsmethoden, die im $provide-Dienst definiert und über angular.module() offengelegt werden. Die Hauptgründe für die Verwendung von $provide im Vergleich zu den Methoden service() und factory() sind beispielsweise die Konfiguration des Dienstes vor seiner Instanziierung. Es mag zwar fortgeschrittenere Anwendungsfälle für die Verwendung von $provide geben, aber ich bin bei der Entwicklung normaler Anwendungen noch nicht darauf gestoßen und ich bin sicher, dass sie auch nicht oft vorkommen werden. Eine der Methoden, die ganz unten in der $provide-Dokumentation aufgeführt sind, ist die Methode decorate(). Sie sieht nicht nach viel aus (schließlich steht sie ganz unten), aber ihre Dokumentation deutet darauf hin, dass sie sehr leistungsfähig ist:

"Ein Service-Dekorator fängt die Erstellung eines Dienstes ab und ermöglicht es, das Verhalten des Dienstes außer Kraft zu setzen oder zu ändern. Das vom Dekorator zurückgegebene Objekt kann der ursprüngliche Dienst sein oder ein neues Dienstobjekt, das den ursprünglichen Dienst ersetzt oder umhüllt und an ihn delegiert."

Dem ist nichts hinzuzufügen. Sie können decorate() verwenden, um das Verhalten von Diensten zu ändern, zu ergänzen oder vollständig zu ersetzen, ohne dass Sie den Code bearbeiten müssen. Das gilt für jeden Code, der nicht Ihr eigener ist - für AngularJS Kerndienste, aber auch für Bibliotheken von Drittanbietern. Es ist das Äquivalent zum Überschreiben von Methoden in OO-Sprachen oder zum Monkey-Patching in dynamischeren Sprachen. "Ist das nicht böse?", höre ich Sie fragen. Wie bei jeder Frage, die mit Programmierung zu tun hat, lautet die einzig richtige Antwort: Es kommt darauf an. Ich werde Ihnen einige praktische Beispiele dafür geben, wann die Verwendung von decorate() meiner Meinung nach angemessen ist. In einem zukünftigen Blog-Beitrag werde ich dieses Beispiel weiter ausbauen und zeigen, wie relativ einfacher Code Ihre gesamte Anwendungsarchitektur positiv beeinflussen kann. Hier ein praktisches Beispiel, das sich nahtlos an meinen vorherigen Blog über Angular Promises anschließt: Dekorieren Sie $q, um dem Promise-Objekt Methoden hinzuzufügen. Die promise API selbst definiert nur eine Methode: then(). $q fügt ein paar einfache Methoden wie catch() und finally() hinzu, aber für Ihre eigene Anwendung können Sie noch ein paar mehr hinzufügen. Wenn Sie in Ihrer AngularJS-Anwendung schon eine Weile mit Versprechen arbeiten, haben Sie wahrscheinlich bemerkt, dass einige Operationen ziemlich häufig vorkommen: Zuweisung des Ergebnisses des Versprechens an den Bereich (oder ein beliebiges Objekt), Protokollierung des Ergebnisses in der Konsole oder Aufruf einer anderen Methode. Mit decorate() können wir dem promise-Objekt Methoden hinzufügen, um diese Vorgänge zu vereinfachen. Hier ist ein Teil des Codes aus meinem vorherigen Beitrag. Wir fügen eine Methode zu $q hinzu, um die Notwendigkeit eines Rückrufs zu beseitigen: [javascript] CustomerService.getCustomer(currentCustomer) .then(CartService.getCart) .then(function(cart) { $scope.cart = cart; }) .catch($log.error); [/javascript] Als Erstes müssen wir ein paar Formalitäten erledigen: Wir erstellen eine Funktion, die dem promise-Objekt unsere Methoden hinzufügt, und ersetzen dann alle Standardmethoden des promise. Beachten Sie, dass sich die Dekorationsfunktion auch wieder auf die angegebene promise.then-Methode bezieht, damit unsere Anpassungen nicht weiter unten in der Versprechenskette verloren gehen: [javascript] angular.module('ngPromiseDsl', []) .config(function ($provide) { $provide.decorator('$q', function ($delegate, $location) { // Dekorationsmethode function decoratePromise(promise) { var then = promise.then; // Überschreiben Sie promise.then. Beachten Sie, dass die benutzerdefinierten Methoden von $q (.catch und .finally) durch die Verwendung von .then selbst implementiert werden, so dass auch sie abgedeckt sind. promise.then = function (thenFn, errFn, notifyFn) { return decoratePromise(then(thenFn, errFn, notifyFn)); }; Versprechen zurückgeben; } // $qs Methoden des Deferred Object verpacken und überschreiben var defer = $delegate.defer, when = $delegate.when, reject = $delegate.reject, all = $delegate.all; $delegate.defer = function () { var deferred = aufschieben(); decoratePromise(deferred.promise); zurückgestellt; }; $delegate.when = function () { return decoratePromise(when.apply(this, arguments)); }; $delegate.reject = function () { return decoratePromise(reject.apply(this, arguments)); }; $delegate.all = function () { return decoratePromise(all.apply(this, arguments)); }; return $delegate; }); }); [/javascript] Mit dieser Grundstruktur können wir nun Methoden hinzufügen. Wie ich bereits erwähnt habe, besteht eine der häufigsten Verwendungen einer then() -Funktion darin, das Ergebnis auf den Bereich (oder ein anderes Objekt) zu setzen. Dies ist ein ziemlich trivialer Vorgang und es ist ziemlich einfach, ihn mit Hilfe unseres Dekorators dem Versprechen-Objekt hinzuzufügen: [javascript]function decoratePromise(promise) { var then = promise.then; promise.then = function (thenFn, errFn, notifyFn) { return decoratePromise(then(thenFn, errFn, notifyFn)); }; // weist den Wert, der an .then angegebenen Wert bei der Auflösung des Versprechens dem angegebenen Objekt unter dem angegebenen varName promise.thenSet = function (obj, varName) { return promise.then(function (value) { obj[varName] = value; return value; }); }; return promise; } [/javascript] Das ist alles. Fügen Sie diesen .config-Block in die Moduldefinition Ihrer Anwendung ein oder erstellen Sie ein neues Modul und fügen Sie ihm eine Abhängigkeit hinzu, damit Sie ihn in Ihrer gesamten Anwendung verwenden können. Hier sehen Sie denselben Code, jetzt mit unserer neuen thenSet-Methode: [javascript] CustomerService.getCustomer(currentCustomer) .then(CartService.getCart) .thenSet($scope, 'cart') .catch($log.error); [/javascript] Dieses Beispiel kann auf vielfältige Weise erweitert werden, um Versprechen mit nützlichen Hilfsmitteln zu versehen. In meinem aktuellen Projekt haben wir dem Promise-Objekt eine Reihe von Methoden hinzugefügt, die es uns ermöglichen, die Anzahl der Callback-Definitionen in unseren Controllern zu reduzieren und so einen saubereren, besser lesbaren Code zu erstellen.

Das Ersetzen benutzerdefinierter Rückrufe durch benannte Methoden ermöglicht einen funktionelleren Programmierstil und erlaubt es den Lesern, den Code als eine Liste von "Was" statt von "Wie" zu lesen und zu schreiben - und er ist außerdem vollständig asynchron. Die Erweiterung von $q ist jedoch nur der Anfang: Jeder Angular-Dienst kann für verschiedene Zwecke erweitert werden - fügen Sie Leistungsüberwachung und Protokollierung zu $http hinzu, setzen Sie allgemeine Präfixe oder feste Eigenschaften für $resource-URLs oder Template-Pfade, was immer Sie wollen. Hinterlassen Sie in den Kommentaren eine Bemerkung darüber, wie Sie decorate() verwendet haben, um eine bessere Anwendung zu erstellen. Bleiben Sie dran für einen kommenden Beitrag, in dem ich ein kleines Open-Source-Projekt veröffentliche, das die Promise-Objekte von Angular um eine Reihe hilfreicher Methoden zur Durchführung gängiger Aufgaben erweitert. Weitere Lektüre, Ressourcen, hilfreiche Links:

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.