J'ai vu angular.factory () et angular.service () utilisés pour déclarer des services; cependant, je ne trouve angular.service
nulle part dans la documentation officielle.
Quelle est la différence entre les deux méthodes?
Qui devrait être utilisé pour quoi (en supposant qu'ils font des choses différentes)?
Réponses:
J'ai eu du mal à m'enrouler autour de ce concept jusqu'à ce que je le mette de cette façon:
Service : la fonction que vous écrivez sera nouvelle :
Factory : la fonction (constructeur) que vous écrivez sera invoquée :
Ce que vous en faites dépend de vous, mais il existe des modèles utiles ...
Telles que l'écriture d'une fonction de service pour exposer une API publique:
Ou en utilisant une fonction d' usine pour exposer une API publique:
Ou en utilisant une fonction d' usine pour renvoyer un constructeur:
Lequel utiliser? ...
Vous pouvez accomplir la même chose avec les deux. Cependant, dans certains cas, l' usine vous donne un peu plus de flexibilité pour créer un injectable avec une syntaxe plus simple. En effet, alors que myInjectedService doit toujours être un objet, myInjectedFactory peut être un objet, une référence de fonction ou n'importe quelle valeur. Par exemple, si vous avez écrit un service pour créer un constructeur (comme dans le dernier exemple ci-dessus), il devrait être instancié comme suit:
ce qui est sans doute moins souhaitable que cela:
(Mais vous devez vous méfier de l'utilisation de ce type de modèle en premier lieu, car les nouveaux objets dans vos contrôleurs créent des dépendances difficiles à suivre qui sont difficiles à simuler pour les tests. Mieux vaut qu'un service gère une collection d'objets pour que d'utiliser
new()
wily-nilly.)Encore une chose, ce sont tous des singletons ...
Gardez également à l'esprit que dans les deux cas, angular vous aide à gérer un singleton. Peu importe où ou combien de fois vous injectez votre service ou fonction, vous obtiendrez la même référence au même objet ou fonction. (À l'exception d'une usine qui renvoie simplement une valeur comme un nombre ou une chaîne. Dans ce cas, vous obtiendrez toujours la même valeur, mais pas une référence.)
la source
new fn()
, ils doivent donc renvoyer une instance.Tout simplement ..
la source
Voici les principales différences:
Prestations de service
Syntaxe:
module.service( 'serviceName', function );
Résultat: lorsque vous déclarez serviceName comme argument injectable, vous recevrez l' instance d'une fonction passée à
module.service
.Utilisation: pourrait être utile pour partager des fonctions utilitaires qu'il est utile d'invoquer en ajoutant simplement
( )
à la référence de fonction injectée. Peut également être exécuté avecinjectedArg.call( this )
ou similaire.Des usines
Syntaxe:
module.factory( 'factoryName', function );
Résultat: lorsque vous déclarez factoryName en tant qu'argument injectable, vous recevrez la valeur renvoyée en appelant la référence de fonction passée à
module.factory
.Utilisation: pourrait être utile pour renvoyer une fonction «classe» qui peut ensuite être renouvelée pour créer des instances.
Voici un exemple d'utilisation de services et d'usine . En savoir plus sur AngularJS Service vs Factory .
Vous pouvez également consulter la documentation AngularJS et une question similaire sur stackoverflow confus à propos du service par rapport à l'usine .
la source
$providers
tout le temps.this.myFunc = function(){}
dans votre service (vous évite d'écrire du code pour créer l'objet comme vous le feriez avec une usine ).TL; DR
1) Lorsque vous utilisez une usine, vous créez un objet, lui ajoutez des propriétés, puis retournez ce même objet. Lorsque vous transmettez cette usine à votre contrôleur, ces propriétés sur l'objet seront désormais disponibles dans ce contrôleur via votre usine.
2) Lorsque vous utilisez le service , Angular l'instancie en arrière-plan avec le «nouveau» mot clé. Pour cette raison, vous ajouterez des propriétés à «ceci» et le service renverra «ceci». Lorsque vous transmettez le service à votre contrôleur, ces propriétés sur «ceci» seront désormais disponibles sur ce contrôleur via votre service.
Non TL; DR
1) Les
usines d' usine sont le moyen le plus utilisé pour créer et configurer un service. Il n'y a vraiment pas beaucoup plus que ce que le TL; DR a dit. Il vous suffit de créer un objet, d'y ajouter des propriétés, puis de renvoyer ce même objet. Ensuite, lorsque vous passez l'usine dans votre contrôleur, ces propriétés sur l'objet seront désormais disponibles dans ce contrôleur via votre usine. Un exemple plus détaillé est présenté ci-dessous.
Maintenant, quelles que soient les propriétés que nous attachons au «service», nous serons disponibles lorsque nous passerons «myFactory» dans notre contrôleur.
Ajoutons maintenant quelques variables «privées» à notre fonction de rappel. Celles-ci ne seront pas directement accessibles depuis le contrôleur, mais nous finirons par mettre en place des méthodes getter / setter sur 'service' pour pouvoir modifier ces variables 'privées' si nécessaire.
Ici, vous remarquerez que nous n'attachons pas ces variables / fonctions au «service». Nous les créons simplement pour les utiliser ou les modifier ultérieurement.
Maintenant que nos variables et fonctions auxiliaires / privées sont en place, ajoutons quelques propriétés à l'objet «service». Quoi que nous mettions sur «service», nous serons en mesure d'utiliser directement le contrôleur dans lequel nous passerons «myFactory».
Nous allons créer des méthodes setArtist et getArtist qui renvoient ou définissent simplement l'artiste. Nous allons également créer une méthode qui appellera l'API iTunes avec notre URL créée. Cette méthode va retourner une promesse qui se réalisera une fois que les données seront revenues de l'API iTunes. Si vous n'avez pas beaucoup d'expérience dans l'utilisation des promesses dans Angular, je vous recommande fortement de les approfondir.
Ci-dessous, setArtist accepte un artiste et vous permet de définir l'artiste. getArtist renvoie l'artiste callItunes appelle d'abord makeUrl () afin de construire l'URL que nous utiliserons avec notre requête $ http. Ensuite, il configure un objet de promesse, fait une demande $ http avec notre URL finale, puis parce que $ http renvoie une promesse, nous sommes en mesure d'appeler .success ou .error après notre demande. Nous résolvons ensuite notre promesse avec les données iTunes, ou nous la rejetons avec un message disant «Il y a eu une erreur».
Maintenant, notre usine est terminée. Nous pouvons désormais injecter «myFactory» dans n'importe quel contrôleur et nous pourrons ensuite appeler nos méthodes que nous avons attachées à notre objet de service (setArtist, getArtist et callItunes).
Dans le contrôleur ci-dessus, nous injectons dans le service «myFactory». Nous définissons ensuite des propriétés sur notre objet $ scope qui proviennent de données de «myFactory». Le seul code délicat ci-dessus est si vous n'avez jamais traité de promesses auparavant. Parce que callItunes renvoie une promesse, nous sommes en mesure d'utiliser la méthode .then () et de définir $ scope.data.artistData uniquement une fois que notre promesse est remplie avec les données iTunes. Vous remarquerez que notre contrôleur est très «mince». Toutes nos données logiques et persistantes se trouvent dans notre service, pas dans notre contrôleur.
2) Service
La chose la plus importante à savoir lors de la création d'un service est peut-être qu'il est instancié avec le «nouveau» mot clé. Pour vous, gourous de JavaScript, cela devrait vous donner une grande idée de la nature du code. Pour ceux d'entre vous qui ont peu d'expérience en JavaScript ou pour ceux qui ne connaissent pas trop ce que fait le `` nouveau '' mot clé, passons en revue quelques principes fondamentaux de JavaScript qui nous aideront éventuellement à comprendre la nature d'un service.
Pour vraiment voir les changements qui se produisent lorsque vous appelez une fonction avec le mot-clé `` nouveau '', créons une fonction et appelez-la avec le mot clé `` nouveau '', puis montrons ce que fait l'interpréteur lorsqu'il voit le mot clé `` nouveau ''. Les résultats finaux seront les mêmes.
Créons d'abord notre constructeur.
Il s'agit d'une fonction constructeur JavaScript typique. Désormais, chaque fois que nous invoquerons la fonction Person à l'aide du mot-clé 'new', 'this' sera lié à l'objet nouvellement créé.
Ajoutons maintenant une méthode sur le prototype de notre Person afin qu'elle soit disponible sur chaque instance de notre 'classe' Person.
Maintenant, comme nous avons placé la fonction sayName sur le prototype, chaque instance de Person pourra appeler la fonction sayName afin d'alerter le nom de cette instance.
Maintenant que nous avons notre fonction constructeur Person et notre fonction sayName sur son prototype, créons en fait une instance de Person puis appelons la fonction sayName.
Donc, tous ensemble, le code pour créer un constructeur Person, ajouter une fonction à son prototype, créer une instance Person, puis appeler la fonction sur son prototype ressemble à ceci.
Voyons maintenant ce qui se passe réellement lorsque vous utilisez le «nouveau» mot clé en JavaScript. La première chose que vous devriez remarquer est qu'après avoir utilisé 'new' dans notre exemple, nous pouvons appeler une méthode (sayName) sur 'tyler' comme si c'était un objet - c'est parce que c'est le cas. Donc, tout d'abord, nous savons que notre constructeur Person retourne un objet, que nous puissions le voir dans le code ou non. Deuxièmement, nous savons que notre fonction sayName étant située sur le prototype et non directement sur l'instance Person, l'objet renvoyé par la fonction Person doit être délégué à son prototype en cas d'échec des recherches. En termes plus simples, lorsque nous appelons tyler.sayName (), l'interpréteur dit «OK, je vais regarder l'objet 'tyler' que nous venons de créer, localiser la fonction sayName, puis l'appeler. Attendez une minute, je ne le vois pas ici - tout ce que je vois c'est le nom et l'âge, permettez-moi de vérifier le prototype. Ouais, on dirait que c'est sur le prototype, permettez-moi de l'appeler. ”.
Vous trouverez ci-dessous un code permettant de savoir ce que le «nouveau» mot clé fait réellement en JavaScript. Il s'agit essentiellement d'un exemple de code du paragraphe ci-dessus. J'ai mis la «vue interprète» ou la façon dont l'interprète voit le code à l'intérieur des notes.
Ayant maintenant cette connaissance de ce que le «nouveau» mot clé fait vraiment en JavaScript, la création d'un service en angulaire devrait être plus facile à comprendre.
La chose la plus importante à comprendre lors de la création d'un service est de savoir que les services sont instanciés avec le «nouveau» mot clé. En combinant ces connaissances avec nos exemples ci-dessus, vous devez maintenant reconnaître que vous attacherez vos propriétés et méthodes directement à «ceci» qui sera ensuite renvoyé par le service lui-même. Jetons un coup d'oeil à cela en action.
Contrairement à ce que nous avons fait à l'origine avec l'exemple Factory, nous n'avons pas besoin de créer un objet puis de le renvoyer car, comme mentionné plusieurs fois auparavant, nous avons utilisé le mot-clé 'new' pour que l'interpréteur crée cet objet, le déléguer à c'est un prototype, puis retournez-le sans que nous ayons à faire le travail.
Tout d'abord, créons notre fonction «privée» et d'assistance. Cela devrait sembler très familier puisque nous avons fait exactement la même chose avec notre usine. Je ne vais pas expliquer ce que fait chaque ligne ici parce que je l'ai fait dans l'exemple d'usine, si vous êtes confus, relisez l'exemple d'usine.
Maintenant, nous allons attacher toutes nos méthodes qui seront disponibles dans notre contrôleur à «ceci».
Maintenant, tout comme dans notre usine, setArtist, getArtist et callItunes seront disponibles dans le contrôleur dans lequel nous transmettons myService. Voici le contrôleur myService (qui est presque exactement le même que notre contrôleur d'usine).
Comme je l'ai mentionné précédemment, une fois que vous comprenez vraiment ce que le «nouveau» fait, les services sont presque identiques aux usines d'Angular.
la source
L'indice est dans le nom
Les services et les usines sont similaires. Les deux produiront un objet singleton qui peut être injecté dans d'autres objets, et sont donc souvent utilisés de manière interchangeable.
Ils sont destinés à être utilisés sémantiquement pour implémenter différents modèles de conception.
Les services sont destinés à implémenter un modèle de service
Un modèle de service est un modèle dans lequel votre application est divisée en unités de fonctionnalité logiquement cohérentes. Un exemple peut être un accesseur API ou un ensemble de logique métier.
Ceci est particulièrement important dans Angular car les modèles Angular ne sont généralement que des objets JSON extraits d'un serveur, et nous avons donc besoin d'un endroit pour mettre notre logique métier.
Voici un service Github par exemple. Il sait parler à Github. Il connaît les URL et les méthodes. Nous pouvons l'injecter dans un contrôleur, et il générera et retournera une promesse.
Les usines mettent en œuvre un modèle d'usine
Les usines, d'autre part, sont destinées à mettre en œuvre un modèle d'usine. Un modèle d'usine dans lequel nous utilisons une fonction d'usine pour générer un objet. En règle générale, nous pouvons l'utiliser pour créer des modèles. Voici une fabrique qui renvoie un constructeur Author:
Nous utiliserions ceci comme ceci:
Notez que les usines renvoient également des singletons.
Les usines peuvent renvoyer un constructeur
Parce qu'une usine retourne simplement un objet, elle peut retourner n'importe quel type d'objet que vous aimez, y compris une fonction constructeur, comme nous le voyons ci-dessus.
Les usines renvoient un objet; les services sont renouvelables
Une autre différence technique réside dans la composition des services et des usines. Une fonction de service sera nouvellement créée pour générer l'objet. Une fonction d'usine sera appelée et retournera l'objet.
Cela signifie que dans un service, nous ajoutons à "ceci" qui, dans le contexte d'un constructeur, pointera vers l'objet en construction.
Pour illustrer cela, voici le même objet simple créé à l'aide d'un service et d'une fabrique:
la source
Author
paramètre d'injecteur doit êtrePerson
.Toutes les réponses ici semblent concerner le service et l'usine, et c'est valable puisque c'est ce qui était demandé. Mais il est également important de garder à l' esprit qu'il ya plusieurs autres , y compris
provider()
,value()
etconstant()
.La clé à retenir est que chacun est un cas particulier de l'autre. Chaque cas spécial dans la chaîne vous permet de faire la même chose avec moins de code. Chacun ayant également une limitation supplémentaire.
Pour décider quand utiliser lequel vous venez de voir lequel vous permet de faire ce que vous voulez en moins de code. Voici une image illustrant à quel point ils sont similaires:
Pour une ventilation complète étape par étape et une référence rapide de l'utilisation de chacun, vous pouvez visiter le blog d'où j'ai obtenu cette image:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
la source
app.factory ('fn', fn) vs app.service ('fn', fn)
Construction
Avec les usines, Angular invoquera la fonction pour obtenir le résultat. C'est le résultat qui est mis en cache et injecté.
Avec les services, Angular invoquera la fonction constructeur en appelant new . La fonction construite est mise en cache et injectée.
la mise en oeuvre
Les usines renvoient généralement un littéral objet parce que la valeur de retour est ce qui est injecté dans les contrôleurs, les blocs d'exécution, les directives, etc.
Les fonctions de service ne renvoient généralement rien. Au lieu de cela, ils effectuent l'initialisation et exposent des fonctions. Les fonctions peuvent également référencer «this» car elles ont été construites à l'aide de «new».
Conclusion
Quand il s'agit d'utiliser des usines ou des services, ils sont tous deux très similaires. Ils sont injectés dans des contrôleurs, des directives, un bloc d'exécution, etc., et utilisés dans le code client à peu près de la même manière. Ils sont également tous deux singletons - ce qui signifie que la même instance est partagée entre tous les endroits où le service / l'usine est injecté.
Alors, que devriez-vous préférer? L'un ou l'autre - ils sont tellement similaires que les différences sont insignifiantes. Si vous choisissez l'un plutôt que l'autre, sachez simplement comment ils sont construits, afin de pouvoir les implémenter correctement.
la source
J'ai passé quelque temps à essayer de comprendre la différence.
Et je pense que la fonction d'usine utilise le modèle de module et la fonction de service utilise le modèle de constructeur de script Java standard.
la source
Le modèle d'usine est plus flexible car il peut renvoyer des fonctions et des valeurs ainsi que des objets.
Il n'y a pas beaucoup d'intérêt dans le modèle de service à mon humble avis, car tout ce qu'il fait, vous pouvez le faire aussi facilement avec une usine. Les exceptions peuvent être:
On peut dire que le modèle de service est un moyen légèrement plus agréable de créer un nouvel objet d'un point de vue syntaxique, mais il est également plus coûteux à instancier. D'autres ont indiqué que angular utilise "new" pour créer le service, mais ce n'est pas tout à fait vrai - il n'est pas en mesure de le faire car chaque constructeur de service a un nombre différent de paramètres. Ce que fait réellement angulaire est d'utiliser le modèle d'usine en interne pour envelopper votre fonction constructeur. Ensuite, il fait un peu de jiggery intelligent pour simuler le "nouvel" opérateur de javascript, invoquant votre constructeur avec un nombre variable d'arguments injectables - mais vous pouvez laisser cette étape si vous utilisez directement le modèle d'usine, augmentant ainsi très légèrement l'efficacité de votre code.
la source
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 } }); }
Alors que MyFactory et MyService utilisent un prototype, MyFactory prend toujours un coup de performance d'avoir à construire l'objet qui est retourné. Dans les deux exemples, ils ont des utilisateurs privés, mais dans MyService, il n'y a relativement aucune différence de performances.MyFactory(someArgument)
(ex$http()
). Ce n'est pas possible avec un service que vous seriez référencez le constructeur:MyService(someArgument)
.