Ich habe sowohl angle.factory () als auch angle.service () gesehen, die zum Deklarieren von Diensten verwendet wurden. Ich kann jedoch angular.service
nirgendwo in der offiziellen Dokumentation finden.
Was ist der Unterschied zwischen den beiden Methoden?
Welche sollten für was verwendet werden (vorausgesetzt, sie machen verschiedene Dinge)?
angularjs
angular-services
Jacob
quelle
quelle
Antworten:
Ich hatte Probleme, mich mit diesem Konzept zu beschäftigen, bis ich es mir so vorstellte:
Service : Die Funktion , die Sie schreiben, wird neu erstellt :
Factory : Die von Ihnen geschriebene Funktion (Konstruktor) wird aufgerufen :
Was Sie damit machen, liegt bei Ihnen, aber es gibt einige nützliche Muster ...
Beispiel: Schreiben einer Servicefunktion , um eine öffentliche API verfügbar zu machen:
Oder verwenden Sie eine Factory- Funktion, um eine öffentliche API verfügbar zu machen:
Oder verwenden Sie eine Factory- Funktion, um einen Konstruktor zurückzugeben:
Welches zu verwenden? ...
Mit beiden können Sie dasselbe erreichen. In einigen Fällen bietet Ihnen die Factory jedoch etwas mehr Flexibilität, um ein Injectable mit einer einfacheren Syntax zu erstellen. Das liegt daran, dass myInjectedService immer ein Objekt sein muss, myInjectedFactory jedoch ein Objekt, eine Funktionsreferenz oder ein beliebiger Wert sein kann. Wenn Sie beispielsweise einen Dienst zum Erstellen eines Konstruktors geschrieben haben (wie im letzten Beispiel oben), muss dieser wie folgt instanziiert werden:
was wohl weniger wünschenswert ist als dies:
(Sie sollten jedoch in erster Linie vorsichtig sein, wenn Sie diese Art von Muster verwenden, da neue Objekte in Ihren Controllern schwer zu verfolgende Abhängigkeiten erzeugen, die zum Testen schwer zu verspotten sind. Besser, ein Dienst verwaltet eine Sammlung von Objekten für Sie als
new()
wily-nilly verwenden.)Eine weitere Sache, sie sind alle Singletons ...
Denken Sie auch daran, dass Angular Ihnen in beiden Fällen bei der Verwaltung eines Singletons hilft. Unabhängig davon, wo oder wie oft Sie Ihren Dienst oder Ihre Funktion einspeisen, erhalten Sie denselben Verweis auf dasselbe Objekt oder dieselbe Funktion. (Mit der Ausnahme, dass eine Factory einfach einen Wert wie eine Zahl oder eine Zeichenfolge zurückgibt. In diesem Fall erhalten Sie immer den gleichen Wert, jedoch keine Referenz.)
quelle
new fn()
, sodass sie eine Instanz zurückgeben müssen.Einfach gesagt ..
quelle
Hier sind die Hauptunterschiede:
Dienstleistungen
Syntax:
module.service( 'serviceName', function );
Ergebnis: Wenn Sie serviceName als injizierbares Argument deklarieren, erhalten Sie die Instanz einer Funktion, an die übergeben wird
module.service
.Verwendung: Kann nützlich sein, um Dienstprogrammfunktionen freizugeben, die durch einfaches Anhängen
( )
an die Referenz der injizierten Funktion aufgerufen werden können. Könnte auch mitinjectedArg.call( this )
oder ähnlich ausgeführt werden.Fabriken
Syntax:
module.factory( 'factoryName', function );
Ergebnis: Wenn factoryName als injizierbare Argument deklarieren Sie mit dem zur Verfügung gestellt werden Wert, der durch den Aufruf der Funktion Referenz zurückgegeben wird weitergegeben
module.factory
.Verwendung: Kann nützlich sein, um eine ' Klassen' - Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erstellen.
Hier ist ein Beispiel für die Verwendung von Services und Factory . Lesen Sie mehr über AngularJS Service vs Factory .
Sie können auch die AngularJS-Dokumentation und ähnliche Fragen zum Stackoverflow überprüfen, die hinsichtlich Service und Factory verwirrt sind .
quelle
$providers
ganze Zeit zu verwenden.this.myFunc = function(){}
in Ihren Dienst schreiben (erspart Ihnen das Schreiben von Code, um das Objekt zu erstellen, wie Sie es mit einer Factory tun müssten ).TL; DR
1) Wenn Sie eine Factory verwenden , erstellen Sie ein Objekt, fügen Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie diese Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar.
2) Wenn Sie Service verwenden , instanziiert Angular ihn hinter den Kulissen mit dem Schlüsselwort 'new'. Aus diesem Grund fügen Sie 'this' Eigenschaften hinzu, und der Dienst gibt 'this' zurück. Wenn Sie den Dienst an Ihren Controller übergeben, sind diese Eigenschaften für "this" jetzt über Ihren Dienst auf diesem Controller verfügbar.
Nicht TL; DR
1) Factory
Factories sind die beliebteste Methode zum Erstellen und Konfigurieren eines Dienstes. Es gibt wirklich nicht viel mehr als das, was die TL gesagt hat; DR. Sie erstellen einfach ein Objekt, fügen ihm Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie dann die Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar. Ein ausführlicheres Beispiel finden Sie unten.
Jetzt stehen uns alle Eigenschaften zur Verfügung, die wir an 'service' anhängen, wenn wir 'myFactory' an unseren Controller übergeben.
Fügen wir nun unserer Rückruffunktion einige 'private' Variablen hinzu. Auf diese kann vom Controller aus nicht direkt zugegriffen werden, aber wir werden eventuell einige Getter / Setter-Methoden für 'service' einrichten, um diese 'privaten' Variablen bei Bedarf ändern zu können.
Hier werden Sie feststellen, dass wir diese Variablen / Funktionen nicht an 'service' anhängen. Wir erstellen sie einfach, um sie später entweder zu verwenden oder zu ändern.
Nachdem unsere Hilfs- / privaten Variablen und Funktionen vorhanden sind, fügen wir dem 'service'-Objekt einige Eigenschaften hinzu. Was auch immer wir auf "Service" setzen, wir können es direkt in dem Controller verwenden, an den wir "myFactory" übergeben.
Wir werden setArtist- und getArtist-Methoden erstellen, die den Künstler einfach zurückgeben oder festlegen. Wir werden auch eine Methode erstellen, die die iTunes-API mit unserer erstellten URL aufruft. Diese Methode wird ein Versprechen zurückgeben, das erfüllt wird, sobald die Daten von der iTunes-API zurückgegeben wurden. Wenn Sie nicht viel Erfahrung mit Versprechungen in Angular haben, empfehle ich Ihnen dringend, sich eingehend mit ihnen zu befassen.
Unten akzeptiert setArtist einen Künstler und ermöglicht es Ihnen, den Künstler festzulegen . getArtist gibt den Künstler zurück. callItunes ruft zuerst makeUrl () auf, um die URL zu erstellen, die wir für unsere $ http-Anfrage verwenden. Anschließend wird ein Versprechungsobjekt eingerichtet, eine $ http-Anfrage mit unserer endgültigen URL gestellt. Da $ http ein Versprechen zurückgibt, können wir nach unserer Anfrage .success oder .error aufrufen. Wir lösen dann unser Versprechen mit den iTunes-Daten oder lehnen es mit der Meldung "Es ist ein Fehler aufgetreten" ab.
Jetzt ist unsere Fabrik fertig. Wir können jetzt 'myFactory' in jeden Controller einfügen und dann unsere Methoden aufrufen, die wir an unser Serviceobjekt angehängt haben (setArtist, getArtist und callItunes).
Im obigen Controller injizieren wir den 'myFactory'-Dienst. Wir legen dann Eigenschaften für unser $ scope-Objekt fest, die aus Daten von 'myFactory' stammen. Der einzige schwierige Code oben ist, wenn Sie sich noch nie mit Versprechungen befasst haben. Da callItunes ein Versprechen zurückgibt, können wir die .then () -Methode verwenden und $ scope.data.artistData erst festlegen, wenn unser Versprechen mit den iTunes-Daten erfüllt ist. Sie werden feststellen, dass unser Controller sehr dünn ist. Alle unsere logischen und persistenten Daten befinden sich in unserem Service, nicht in unserem Controller.
2) Service
Das vielleicht Wichtigste, was Sie beim Erstellen eines Dienstes wissen müssen, ist, dass er mit dem Schlüsselwort "Neu" instanziiert wird. Für Ihre JavaScript-Gurus sollte dies einen großen Hinweis auf die Art des Codes geben. Für diejenigen unter Ihnen mit eingeschränktem Hintergrund in JavaScript oder für diejenigen, die nicht genau wissen, was das 'neue' Schlüsselwort tatsächlich bewirkt, lassen Sie uns einige JavaScript-Grundlagen überprüfen, die uns letztendlich helfen, die Natur eines Dienstes zu verstehen.
Um die Änderungen wirklich zu sehen, die auftreten, wenn Sie eine Funktion mit dem Schlüsselwort 'new' aufrufen, erstellen wir eine Funktion und rufen sie mit dem Schlüsselwort 'new' auf. Zeigen wir dann, was der Interpreter tut, wenn er das Schlüsselwort 'new' sieht. Die Endergebnisse sind beide gleich.
Lassen Sie uns zuerst unseren Konstruktor erstellen.
Dies ist eine typische JavaScript-Konstruktorfunktion. Wenn wir nun die Person-Funktion mit dem Schlüsselwort 'new' aufrufen, wird 'this' an das neu erstellte Objekt gebunden.
Fügen wir nun dem Prototyp unserer Person eine Methode hinzu, damit sie für jede Instanz unserer Personenklasse verfügbar ist.
Da wir nun die Funktion sayName auf den Prototyp setzen, kann jede Instanz von Person die Funktion sayName aufrufen, um den Namen dieser Instanz zu warnen.
Nachdem wir nun unsere Person-Konstruktorfunktion und unsere sayName-Funktion in ihrem Prototyp haben, erstellen wir tatsächlich eine Instanz von Person und rufen dann die sayName-Funktion auf.
Insgesamt sieht der Code zum Erstellen eines Personenkonstruktors, zum Hinzufügen einer Funktion zum Prototyp, zum Erstellen einer Personeninstanz und zum anschließenden Aufrufen der Funktion für den Prototyp folgendermaßen aus.
Schauen wir uns nun an, was tatsächlich passiert, wenn Sie das Schlüsselwort 'new' in JavaScript verwenden. Das erste, was Sie beachten sollten, ist, dass wir nach der Verwendung von 'new' in unserem Beispiel eine Methode (sayName) für 'tyler' aufrufen können, als wäre es ein Objekt - das liegt daran, dass es so ist. Zuerst wissen wir also, dass unser Personenkonstruktor ein Objekt zurückgibt, ob wir das im Code sehen können oder nicht. Zweitens wissen wir, dass das Objekt, das die Person-Funktion zurückgibt, bei fehlgeschlagenen Suchvorgängen an ihren Prototyp delegieren muss, da sich unsere sayName-Funktion auf dem Prototyp und nicht direkt auf der Person-Instanz befindet. Einfacher ausgedrückt, wenn wir tyler.sayName () aufrufen, sagt der Interpreter: „OK, ich werde das soeben erstellte 'tyler'-Objekt betrachten, die Funktion sayName suchen und es dann aufrufen. Moment mal, ich sehe es hier nicht - alles was ich sehe ist Name und Alter, Lassen Sie mich den Prototyp überprüfen. Ja, es sieht so aus, als wäre es auf dem Prototyp, lass es mich nennen. “
Unten finden Sie Code, wie Sie darüber nachdenken können, was das 'neue' Schlüsselwort in JavaScript tatsächlich tut. Es ist im Grunde ein Codebeispiel für den obigen Absatz. Ich habe die 'Interpreter-Ansicht' oder die Art und Weise, wie der Interpreter den Code sieht, in Notizen eingefügt.
Wenn Sie nun wissen, was das 'neue' Schlüsselwort in JavaScript wirklich bewirkt, sollte es einfacher sein, einen Dienst in Angular zu erstellen.
Das Wichtigste, was Sie beim Erstellen eines Dienstes verstehen müssen, ist zu wissen, dass Dienste mit dem Schlüsselwort "Neu" instanziiert werden. Wenn Sie dieses Wissen mit unseren obigen Beispielen kombinieren, sollten Sie jetzt erkennen, dass Sie Ihre Eigenschaften und Methoden direkt an 'this' anhängen, das dann vom Service selbst zurückgegeben wird. Schauen wir uns das in Aktion an.
Im Gegensatz zu dem, was wir ursprünglich mit dem Factory-Beispiel gemacht haben, müssen wir kein Objekt erstellen und dann dieses Objekt zurückgeben, da wir, wie bereits mehrfach erwähnt, das Schlüsselwort 'new' verwendet haben, damit der Interpreter dieses Objekt erstellt und es delegieren lässt Es ist ein Prototyp und wird dann für uns zurückgegeben, ohne dass wir die Arbeit erledigen müssen.
Lassen Sie uns zuerst unsere 'private' und Hilfsfunktion erstellen. Dies sollte sehr vertraut aussehen, da wir mit unserer Fabrik genau dasselbe gemacht haben. Ich werde hier nicht erklären, was jede Zeile tut, da ich das im Fabrikbeispiel getan habe. Wenn Sie verwirrt sind, lesen Sie das Fabrikbeispiel erneut.
Jetzt werden wir alle unsere Methoden, die in unserem Controller verfügbar sein werden, an 'this' anhängen.
Genau wie in unserer Factory sind setArtist, getArtist und callItunes jetzt in jedem Controller verfügbar, an den wir myService übergeben. Hier ist der myService-Controller (der fast genau dem unseres werkseitigen Controllers entspricht).
Wie ich bereits erwähnt habe, sind Services, sobald Sie wirklich verstanden haben, was "neu" macht, fast identisch mit Fabriken in Angular.
quelle
Der Hinweis ist im Namen
Dienstleistungen und Fabriken ähneln sich. Beide ergeben ein Singleton-Objekt, das in andere Objekte injiziert werden kann und daher häufig austauschbar verwendet wird.
Sie sollen semantisch verwendet werden, um verschiedene Entwurfsmuster zu implementieren.
Services dienen zum Implementieren eines Servicemusters
Ein Servicemuster ist eines, bei dem Ihre Anwendung in logisch konsistente Funktionseinheiten unterteilt ist. Ein Beispiel könnte ein API-Accessor oder eine Reihe von Geschäftslogiken sein.
Dies ist in Angular besonders wichtig, da Angular-Modelle normalerweise nur JSON-Objekte sind, die von einem Server abgerufen werden. Daher müssen wir unsere Geschäftslogik irgendwo platzieren.
Hier ist zum Beispiel ein Github-Service. Es weiß, wie man mit Github spricht. Es kennt URLs und Methoden. Wir können es in einen Controller einspeisen, und es wird ein Versprechen generieren und zurückgeben.
Fabriken implementieren ein Fabrikmuster
Fabriken hingegen sollen ein Fabrikmuster implementieren. Ein Factory-Muster, in dem wir eine Factory-Funktion verwenden, um ein Objekt zu generieren. Normalerweise können wir dies zum Erstellen von Modellen verwenden. Hier ist eine Factory, die einen Author-Konstruktor zurückgibt:
Wir würden dies so nutzen:
Beachten Sie, dass Fabriken auch Singletons zurückgeben.
Fabriken können einen Konstruktor zurückgeben
Da eine Factory einfach ein Objekt zurückgibt, kann sie jeden beliebigen Objekttyp zurückgeben, einschließlich einer Konstruktorfunktion, wie oben dargestellt.
Fabriken geben ein Objekt zurück; Dienstleistungen sind neu
Ein weiterer technischer Unterschied besteht in der Zusammensetzung der Dienstleistungen und Fabriken. Eine Servicefunktion wird neu generiert, um das Objekt zu generieren. Eine Factory-Funktion wird aufgerufen und gibt das Objekt zurück.
Dies bedeutet, dass wir in einem Dienst an "dies" anhängen, das im Kontext eines Konstruktors auf das im Bau befindliche Objekt verweist.
Um dies zu veranschaulichen, ist hier dasselbe einfache Objekt, das mit einem Service und einer Factory erstellt wurde:
quelle
Author
Injektorparameter befinden solltePerson
.Alle Antworten hier scheinen sich auf Service und Fabrik zu beziehen, und das ist gültig, da danach gefragt wurde. Aber es ist auch wichtig , im Auge zu behalten , dass es mehrere andere , einschließlich
provider()
,value()
undconstant()
.Der Schlüssel zum Erinnern ist, dass jeder ein Sonderfall des anderen ist. Jeder Sonderfall in der Kette ermöglicht es Ihnen, dasselbe mit weniger Code zu tun. Jeder hat auch eine zusätzliche Einschränkung.
Um zu entscheiden, wann Sie welche verwenden möchten, sehen Sie nur, welche Sie mit weniger Code tun können, was Sie wollen. Hier ist ein Bild, das zeigt, wie ähnlich sie sind:
Für eine vollständige schrittweise Aufschlüsselung und eine schnelle Referenz, wann sie verwendet werden sollen, können Sie den Blog-Beitrag besuchen, von dem ich dieses Bild erhalten habe:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
quelle
app.factory ('fn', fn) vs. app.service ('fn', fn)
Konstruktion
Bei Fabriken ruft Angular die Funktion auf, um das Ergebnis zu erhalten. Es ist das Ergebnis, das zwischengespeichert und injiziert wird.
Bei Diensten ruft Angular die Konstruktorfunktion auf, indem er new aufruft . Die konstruierte Funktion wird zwischengespeichert und injiziert.
Implementierung
Fabriken typischerweise ein Objektliteral zurück , weil der Rückgabewert ist , was in Controller, führen Blöcke, Richtlinien injiziert ist, usw.
Servicefunktionen geben normalerweise nichts zurück. Stattdessen führen sie eine Initialisierung durch und legen Funktionen offen. Funktionen können auch auf "dies" verweisen, da es mit "neu" erstellt wurde.
Fazit
Wenn es um die Nutzung von Fabriken oder Dienstleistungen geht, sind sich beide sehr ähnlich. Sie werden in Controller, Direktiven, Ausführungsblöcke usw. eingefügt und im Client-Code auf die gleiche Weise verwendet. Sie sind auch beide Singletons - das heißt, dieselbe Instanz wird von allen Stellen gemeinsam genutzt, an denen der Service / die Factory injiziert wird.
Also was solltest du bevorzugen? Entweder eins - sie sind sich so ähnlich, dass die Unterschiede trivial sind. Wenn Sie eine über die andere wählen, achten Sie einfach darauf, wie sie aufgebaut sind, damit Sie sie richtig implementieren können.
quelle
Ich habe einige Zeit damit verbracht, den Unterschied herauszufinden.
Und ich denke, die Factory-Funktion verwendet das Modulmuster und die Servicefunktion verwendet das Standard-Java-Skriptkonstruktormuster.
quelle
Das Factory-Muster ist flexibler, da es Funktionen und Werte sowie Objekte zurückgeben kann.
Das Servicemuster hat meiner Meinung nach nicht viel Sinn, da alles, was es tut, genauso einfach mit einer Fabrik gemacht werden kann. Die Ausnahmen könnten sein:
Das Servicemuster ist wahrscheinlich eine etwas bessere Möglichkeit, ein neues Objekt aus syntaktischer Sicht zu erstellen, aber es ist auch teurer, es zu instanziieren. Andere haben angegeben, dass Angular "new" verwendet, um den Service zu erstellen, aber dies ist nicht ganz richtig - dies ist nicht möglich, da jeder Servicekonstruktor eine andere Anzahl von Parametern hat. Was Angular tatsächlich tut, ist, das Factory-Muster intern zu verwenden, um Ihre Konstruktorfunktion zu verpacken. Dann simuliert es den "neuen" Operator von Javascript, indem es Ihren Konstruktor mit einer variablen Anzahl injizierbarer Argumente aufruft. Sie können diesen Schritt jedoch weglassen, wenn Sie nur das Factory-Muster direkt verwenden, wodurch die Effizienz Ihres Operators geringfügig erhöht wird Code.
quelle
function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; }
function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); }
Während sowohl MyFactory als auch MyService Prototypen verwenden, muss MyFactory immer noch einen Leistungseinbruch hinnehmen, um das zurückgegebene Objekt zu erstellen. In beiden Beispielen haben sie Privaten, aber in MyService gibt es relativ keinen Leistungsunterschied.MyFactory(someArgument)
(ex$http()
). Dies ist mit einem Dienst nicht möglich, da Sie auf den Konstruktor verweisen würden :MyService(someArgument)
.