dependency-injection factory - AngularJS:Service vs fournisseur vs usine




provider difference (25)

Quelles sont les différences entre un Service , un Provider et une Factory dans AngularJS?


Answers

Résumé de la docs.angularjs.org/guide/providers :

  • Il existe cinq types de recettes qui définissent comment créer des objets: Value , Factory , Service , Provider et Constant .
  • Factory et Service sont les recettes les plus couramment utilisées. La seule différence entre eux est que la recette de service fonctionne mieux pour les objets d'un type personnalisé, tandis que la fabrique peut produire des primitives et des fonctions JavaScript.
  • La recette du fournisseur est le type de recette principale et toutes les autres ne sont que du sucre syntaxique.
  • Le fournisseur est le type de recette le plus complexe. Vous n'en avez pas besoin, sauf si vous créez un élément de code réutilisable nécessitant une configuration globale.

Meilleures réponses de SO:

https://stackoverflow.com/a/26924234/165673 (<- GOOD) https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673


Je connais beaucoup d’excellente réponse, mais je dois partager mon expérience d’utilisation de
1. servicepour la plupart des cas de défaut
2. factoryutilisé pour créer le service qui correspond à une instance spécifique

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

et en utilisant:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 

Pour moi, le meilleur moyen de comprendre la différence est:

var service, factory;
service = factory = function(injection) {}

Comment AngularJS instancie des composants particuliers (simplifié):

// service
var angularService = new service(injection);

// factory
var angularFactory = factory(injection);

Ainsi, pour le service, le composant AngularJS devient l'instance d'objet de la classe représentée par la fonction de déclaration de service. Pour l'usine, il s'agit du résultat renvoyé par la fonction de déclaration d'usine. L’usine peut se comporter comme le service:

var factoryAsService = function(injection) {
  return new function(injection) {
    // Service content
  }
}

La façon la plus simple de penser est la suivante:

  • Le service est une instance d'objet singleton. Utilisez les services si vous souhaitez fournir un objet singleton pour votre code.
  • L'usine est une classe. Utilisez des fabriques si vous souhaitez fournir des classes personnalisées pour votre code (impossible avec des services car elles sont déjà instanciées).

L'exemple de «classe» d'usine est fourni dans les commentaires, ainsi que la différence de fournisseur.


Juste pour clarifier les choses, depuis la source AngularJS, vous pouvez voir qu'un service appelle simplement la fonction usine qui à son tour appelle la fonction fournisseur:

function factory(name, factoryFn) { 
    return provider(name, { $get: factoryFn }); 
}

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
}

Service vs fournisseur vs usine:

J'essaie de garder les choses simples. Tout repose sur le concept JavaScript de base.

Tout d’abord, parlons des services dans AngularJS!

Qu'est-ce que le service? Dans AngularJS, Servicen’est rien qu’un objet JavaScript unique qui peut stocker des méthodes ou des propriétés utiles. Cet objet singleton est créé par ngApp (application angulaire) et il est partagé entre tous les contrôleurs de l'application actuelle. Lorsque Angularjs instancie un objet de service, il enregistre cet objet de service avec un nom de service unique. Ainsi, chaque fois que nous avons besoin d’une instance de service, Angular recherche dans le registre ce nom de service et renvoie la référence à l’objet service. De telle sorte que nous puissions appeler une méthode, des propriétés d'accès, etc. sur l'objet de service. Vous vous demandez peut-être si vous pouvez également mettre des propriétés, des méthodes sur l'objet scope des contrôleurs! Alors pourquoi avez-vous besoin d'un objet de service? Answers is: les services sont partagés par plusieurs contrôleurs. Si vous mettez des propriétés / méthodes dans l'objet scope d'un contrôleur, il ne sera disponible que pour l'étendue actuelle.Mais lorsque vous définissez des méthodes, des propriétés sur un objet de service, celui-ci sera disponible de manière globale et sera accessible dans l'étendue de tout contrôleur en injectant ce service.

Ainsi, s’il ya trois contrôleurs, qu’il s’agisse de controllerA, controllerB et controllerC, tous partageront la même instance de service.

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

Comment créer un service?

AngularJS propose différentes méthodes pour enregistrer un service. Ici, nous allons nous concentrer sur trois méthodes usine (..), service (..), fournisseur (..);

Utilisez ce lien pour la référence de code

Fonction d'usine:

Nous pouvons définir une fonction d'usine comme ci-dessous.

factory('serviceName',function fnFactory(){ return serviceInstance;})

AngularJS fournit la méthode 'factory (' serviceName ', fnFactory)' qui prend deux paramètres, serviceName et une fonction JavaScript. Angular crée une instance de service en appelant la fonction fnFactory () comme ci-dessous.

var serviceInstace = fnFactory();

La fonction transmise peut définir un objet et le renvoyer. AngularJS stocke simplement cette référence d'objet à une variable qui est passée en premier argument. Tout ce qui est renvoyé par fnFactory sera lié à serviceInstance. Au lieu de renvoyer un objet, nous pouvons également renvoyer une fonction, des valeurs, etc. Tout ce que nous retournerons sera disponible pour l'instance de service.

Exemple:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

Fonction de service:

service('serviceName',function fnServiceConstructor(){})

C'est l'inverse, nous pouvons enregistrer un service. La seule différence réside dans la manière dont AngularJS tente d'instancier l'objet de service. Cette fois, angular utilise le mot-clé 'new' et appelle la fonction constructeur de la manière suivante.

var serviceInstance = new fnServiceConstructor();

Dans la fonction constructeur, nous pouvons utiliser le mot clé 'this' pour ajouter des propriétés / méthodes à l'objet de service. Exemple:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

Fonction du fournisseur:

La fonction Provider () est un autre moyen de créer des services. Laissons-nous nous intéresser à la création d’un service qui n’affiche que des messages de bienvenue à l’utilisateur. Mais nous souhaitons également fournir une fonctionnalité permettant à l’utilisateur de définir son propre message de bienvenue. En termes techniques, nous voulons créer des services configurables. Comment peut-on le faire ? Il doit y avoir un moyen, pour que l'application puisse transmettre leurs messages d'accueil personnalisés et qu'Angularjs le rende disponible pour la fonction fabrique / constructeur qui crée notre instance de services. Dans un tel cas, la fonction provider () fait le travail. En utilisant la fonction provider (), nous pouvons créer des services configurables.

Nous pouvons créer des services configurables en utilisant la syntaxe de fournisseur indiquée ci-dessous.

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

Comment la syntaxe du fournisseur fonctionne-t-elle en interne?

L'objet 1.Provider est créé à l'aide de la fonction constructeur définie dans notre fonction fournisseur.

var serviceProvider = new serviceProviderConstructor();

2.La fonction que nous avons passée dans app.config () est exécutée. C'est ce qu'on appelle la phase de configuration, et nous avons ici la possibilité de personnaliser notre service.

configureService(serviceProvider);

3.Enfin, l'instance de service est créée en appelant la méthode $ get de serviceProvider.

serviceInstance = serviceProvider.$get()

Exemple de code pour la création de service à l'aide de la syntaxe:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

Démo de travail

Résumé:

Factory utilise une fonction factory qui renvoie une instance de service. serviceInstance = fnFactory ();

Le service utilise une fonction constructeur et Angular appelle cette fonction constructeur à l'aide du mot clé "new" pour créer l'instance de service. serviceInstance = new fnServiceConstructor ();

Fournisseur définit une fonction fournisseurConstructeur, cette fonction fournisseurConstructeur définit une fonction d'usine $ get . Appels angulaires $ get () pour créer l'objet de service. La syntaxe de fournisseur présente l'avantage supplémentaire de configurer l'objet de service avant qu'il ne soit instancié. serviceInstance = $ get ();


1. Les services sont des objets singleton créés le cas échéant et ne sont jamais nettoyés jusqu'à la fin du cycle de vie de l'application (date de fermeture du navigateur). Les contrôleurs sont détruits et nettoyés quand ils ne sont plus nécessaires.

2. Le moyen le plus simple de créer un service consiste à utiliser la méthode factory (). La méthode factory () nous permet de définir un service en renvoyant un objet contenant des fonctions de service et des données de service. La fonction de définition de service est l'endroit où nous plaçons nos services injectables, tels que $ http et $ q. Ex:

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
    // our factory definition
user: {},
setName: function(newName) {
      service.user['name'] = newName;
    },
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });

Utiliser l'usine () dans notre application

Il est facile d’utiliser l’usine dans notre application car nous pouvons simplement l’injecter là où nous en avons besoin au moment de l’exécution.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. La méthode service (), en revanche, nous permet de créer un service en définissant une fonction constructeur. Nous pouvons utiliser un objet prototype pour définir notre service, au lieu d’un objet javascript brut. Semblable à la méthode factory (), nous allons également définir les injectables dans la définition de la fonction.
  2. Le moyen le plus simple de créer un service consiste à utiliser la méthode offer (). C'est le seul moyen de créer un service que nous pouvons configurer à l'aide de la fonction .config (). Contrairement aux méthodes précédentes, nous allons définir les injectables dans une définition de la fonction $ get () définie.

Tous les services sont des singletons ; ils sont instanciés une fois par application. Ils peuvent être de n'importe quel type , qu'il s'agisse d'une primitive, d'un littéral d'objet, d'une fonction ou même d'une instance d'un type personnalisé.

Les méthodes value , factory , service , constant et provider sont toutes des fournisseurs. Ils enseignent à l'injecteur comment instancier les services.

Le plus détaillé, mais aussi le plus complet, est une recette de fournisseur. Les quatre types de recettes restants - Valeur, Usine, Service et Constante - ne sont que du sucre syntaxique en plus d'une recette du fournisseur .

  • La recette de valeur est le cas le plus simple, dans lequel vous instanciez vous-même le service et fournissez la valeur instanciée à l'injecteur.
  • La recette Usine donne à l'injecteur une fonction usine qu'il appelle lorsqu'il doit instancier le service. Lorsqu'elle est appelée, la fonction fabrique crée et renvoie l'instance de service. Les dépendances du service sont injectées en tant qu'arguments des fonctions. Donc, en utilisant cette recette ajoute les capacités suivantes:
    • Possibilité d'utiliser d'autres services (avoir des dépendances)
    • Initialisation du service
    • Initialisation différée / lente
  • La recette de service est presque identique à la recette Usine, mais ici l’injecteur appelle un constructeur avec le nouvel opérateur au lieu d’une fonction usine.
  • La recette du fournisseur est généralement excessive . Il ajoute une couche d'indirection supplémentaire en vous permettant de configurer la création de la fabrique.

    Vous devez utiliser la recette du fournisseur uniquement lorsque vous souhaitez exposer une API pour une configuration à l'échelle de l'application à effectuer avant le démarrage de l'application. Cela n’est généralement intéressant que pour les services réutilisables dont le comportement peut varier légèrement d’une application à l’autre.

  • La recette Constante est semblable à la recette Valeur, sauf qu'elle vous permet de définir les services disponibles dans la phase de configuration . Plus tôt que les services créés à l'aide de la recette Valeur. Contrairement aux valeurs, elles ne peuvent pas être décorées à l'aide d'un decorator .
Voir la documentation du fournisseur .


Toutes les bonnes réponses déjà. J'aimerais ajouter quelques points supplémentaires sur Service et Factory . Avec la différence entre service / usine. Et on peut aussi avoir des questions comme:

  1. Devrais-je utiliser le service ou l'usine? Quelle est la différence?
  2. Est-ce qu'ils font la même chose ou ont le même comportement?

Commençons par la différence entre le service et l’usine:

  1. Les deux sont des singletons : chaque fois que Angular trouve ces dépendances pour la première fois, il crée une instance unique de service / usine. Une fois l'instance créée, la même instance est utilisée indéfiniment.

  2. Peut être utilisé pour modéliser un objet avec un comportement : ils peuvent avoir des méthodes, des variables d'état internes, etc. Bien que la façon dont vous écrivez ce code sera différente.

Prestations de service:

Un service est une fonction constructeur et Angular l'instancie en appelant new yourServiceName(). Cela signifie deux choses.

  1. Les fonctions et les variables d'instance seront les propriétés de this.
  2. Vous n'avez pas besoin de renvoyer une valeur. Quand Angular appelle new yourServiceName(), il recevra l' thisobjet avec toutes les propriétés que vous lui avez assignées.

Exemple d'échantillon:

angular.service('MyService', function() {
  this.aServiceVariable = "Ved Prakash"
  this.aServiceMethod = function() {
    return //code
  };
});

Lorsque Angular injecte ce MyServiceservice dans un contrôleur qui en dépend, celui-ci reçoit un MyServiceappel sur lequel il peut appeler des fonctions, par exemple, MyService.aServiceMethod ().

Soyez prudent avecthis :

Puisque le service construit est un objet, les méthodes qu'il contient peuvent faire référence à cela quand elles sont appelées:

angular.service('ScoreKeeper', function($http) {
  this.score = 0;

  this.getScore = function() {
    return this.score;
  };

  this.setScore = function(newScore) {
    this.score = newScore;
  };

  this.addOne = function() {
    this.score++;
  };
});

Vous pourriez être tenté d'appeler ScoreKeeper.setScoreune chaîne de promesse, par exemple si vous initialisez le score en le saisissant sur le serveur: $http.get('/score').then(ScoreKeeper.setScore).le problème est que ScoreKeeper.setScorecela sera appelé avec thislié à nullet que vous obtiendrez des erreurs. La meilleure façon serait $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Que vous choisissiez ou non d'utiliser cela dans vos méthodes de service, soyez prudent lorsque vous les appelez.

Renvoyer une valeur d'unService :

En raison du fonctionnement des constructeurs JavaScript, si vous renvoyez une valeur complexe à (ie, an Object)partir d'une constructorfonction, l'appelant obtiendra cet objet au lieu de cette instance.

Cela signifie que vous pouvez fondamentalement copier-coller l'exemple d'usine par dessous, remplacer factorypar service, et cela fonctionnera:

angular.service('MyService', function($http) {
  var api = {};

  api.aServiceMethod= function() {
    return $http.get('/users');
  };
  return api;
});

Ainsi, lorsque Angular construira votre service avec le nouveau MyService (), il obtiendra cet objet api au lieu de l'instance MyService.

C'est le comportement de toutes les valeurs complexes (objets, fonctions) mais pas des types primitifs.

Des usines:

Une fabrique est une ancienne fonction qui renvoie une valeur. La valeur de retour est ce qui est injecté dans les choses qui dépendent de l’usine. Un modèle d'usine typique dans Angular consiste à renvoyer un objet avec des fonctions en tant que propriétés, comme ceci:

angular.factory('MyFactory', function($http) {
  var api = {};

  api.aFactoryMethod= function() {
    return $http.get('/users');
  };

  return api;
});

La valeur injectée pour une dépendance d'usine est la valeur de retour de l'usine et il n'est pas nécessaire que ce soit un objet. Ça pourrait être une fonction

Réponses aux questions 1 et 2 ci-dessus:

Pour la plupart, contentez-vous d'utiliser des usines pour tout. Leur comportement est plus facile à comprendre. Il n'y a pas d'autre choix à faire pour renvoyer une valeur ou non, et en plus, aucun bogue à introduire si vous faites la mauvaise chose

Je me réfère toujours à eux comme des «services» quand je parle de les injecter comme des dépendances, cependant.

Le comportement Service / Usine est très similaire, et certaines personnes diront que l’un ou l’autre va bien. C'est un peu vrai, mais je trouve plus facile de suivre les conseils du guide de style de John Papa et de me contenter des usines. **


Ma clarification à ce sujet:

Tous les types mentionnés (service, usine, fournisseur, etc.) ne font que créer et configurer des variables globales (bien entendu globales pour l’ensemble de l’application), tout comme les anciennes variables globales.

Bien que les variables globales ne soient pas recommandées, l'utilisation réelle de ces variables globales consiste à fournir une injection de dépendance en transmettant la variable au contrôleur approprié.

Il existe de nombreux niveaux de complications dans la création des valeurs pour les "variables globales":

  1. Constante
    Ceci définit une constante réelle qui ne devrait pas être modifiée pendant toute l'application, tout comme le sont les constantes d'autres langages (ce qui manque à JavaScript).
  2. Valeur
    Il s'agit d'une valeur ou d'un objet modifiable, qui sert de variable globale, pouvant même être injecté lors de la création d'autres services ou usines (voir plus loin). Cependant, il doit s'agir d'une " valeur littérale ", ce qui signifie qu'il faut écrire la valeur réelle et ne peut utiliser aucune logique de calcul ou de programmation (en d'autres termes, 39 ou myText ou {prop: "valeur"} sont OK, mais 2 +2 n'est pas).
  3. Usine
    Une valeur plus générale, qui peut être calculée immédiatement. Il fonctionne en transmettant une fonction à AngularJS avec la logique nécessaire pour calculer la valeur. AngularJS l'exécute et enregistre la valeur de retour dans la variable nommée.
    Notez qu'il est possible de renvoyer un objet (dans ce cas, il fonctionnera comme un service ) ou une fonction (qui sera enregistrée dans la variable en tant que fonction de rappel).
  4. Un service
    Un service est une version d' usine plus réduite qui n'est valide que lorsque la valeur est un objet. Elle permet d'écrire toute logique directement dans la fonction (comme s'il s'agissait d'un constructeur), ainsi que de déclarer et d'accéder au propriétés de l'objet à l'aide du mot - clé this .
  5. Fournisseur
    Contrairement à un service qui est une version simplifiée de la fabrique , un fournisseur est un moyen plus complexe, mais plus flexible, d'initialiser les variables "globales", la plus grande flexibilité étant la possibilité de définir des valeurs à partir de app.config.
    Cela fonctionne comme si vous utilisiez une combinaison de service et de fournisseur , en transmettant au fournisseur une fonction dont les propriétés sont déclarées à l’aide du mot - clé this , qui peut être utilisé à partir du fichier app.config.
    Ensuite, il doit avoir une fonction $ .get séparée qui est exécutée par AngularJS après avoir défini les propriétés ci-dessus via le app.configfichier, et cette fonction $ .get se comporte exactement comme la fabrique. ci-dessus, en ce sens que sa valeur de retour est utilisée pour initialiser les variables "globales".

Comprendre l'usine, le service et le fournisseur AngularJS

Tous ces éléments sont utilisés pour partager des objets singleton réutilisables. Il est utile de partager du code réutilisable sur votre application / divers composants / modules.

De Docs Service/Factory :

  • Instancié en différé - Angular instancie uniquement un service / une usine lorsqu'un composant d'application en dépend.
  • Singletons - Chaque composant dépendant d'un service obtient une référence à l'instance unique générée par la fabrique de services.

Usine

Une fabrique est une fonction dans laquelle vous pouvez manipuler / ajouter une logique avant de créer un objet, puis l'objet nouvellement créé est renvoyé.

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

Usage

Ce peut être juste un ensemble de fonctions comme une classe. Par conséquent, il peut être instancié dans différents contrôleurs lorsque vous l'injectez dans vos fonctions contrôleur / usine / directive. Il n'est instancié qu'une fois par application.

Un service

Tout en regardant les services, pensez au prototype de tableau. Un service est une fonction qui instancie un nouvel objet à l'aide du mot clé "new". Vous pouvez ajouter des propriétés et des fonctions à un objet de service à l'aide du thismot clé. Contrairement à une fabrique, il ne renvoie rien (il retourne un objet contenant des méthodes / propriétés).

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

Usage

Utilisez-le lorsque vous devez partager un seul objet dans toute l'application. Par exemple, informations d'utilisateur authentifiées, méthodes / données partageables, fonctions utilitaires, etc.

Fournisseur

Un fournisseur est utilisé pour créer un objet de service configurable. Vous pouvez configurer le paramètre de service à partir de la fonction de configuration. Il retourne une valeur en utilisant la $get()fonction. La $getfonction est exécutée lors de la phase d'exécution en mode angulaire.

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

Usage

Lorsque vous devez fournir une configuration par module pour votre objet de service avant de le rendre disponible, par exemple. supposons que vous souhaitiez définir votre URL API en fonction de votre environnement dev, stageouprod

REMARQUE

Seul le fournisseur sera disponible dans la phase de configuration angulaire, alors que le service et l’usine ne le sont pas.

J'espère que cela a éclairci votre compréhension de Factory, Service and Provider .


En fonction des objectifs de la mémoire, les contrôleurs ne sont instanciés que lorsqu'ils sont nécessaires et ignorés lorsqu'ils ne le sont pas. De ce fait, chaque fois que vous changez de route ou rechargez une page, Angular nettoie le contrôleur actuel. Cependant, les services permettent de conserver les données pendant toute la durée de vie d'une application, tout en pouvant être utilisés de manière cohérente sur différents contrôleurs.

Angular nous fournit trois façons de créer et d’enregistrer notre propre service.

1) usine

2) service

3) fournisseur

Factory : Une factory est une fonction simple qui vous permet d'ajouter une logique avant de créer l'objet. Il retourne l'objet créé.

C'est juste une collection de fonctions comme une classe. Par conséquent, il peut être instancié dans différents contrôleurs lorsque vous l'utilisez avec la fonction constructeur.

Service : un service est une fonction constructeur qui crée l'objet à l'aide d'un nouveau mot clé. Vous pouvez ajouter des propriétés et des fonctions à un objet de service à l'aide de ce mot clé. Contrairement à l'usine, il ne retourne rien.

C'est un objet singleton. Utilisez-le lorsque vous devez partager un seul objet dans l'application. Par exemple, les détails de l'utilisateur authentifié.

Fournisseur : un fournisseur est utilisé pour créer un objet de service configurable. Il retourne une valeur en utilisant la fonction $ get ().

Lorsque vous devez fournir une configuration par module pour votre objet de service avant de le rendre disponible.

Exécutez le code suivant et voyez la sortie.

<!DOCTYPE html>
<html ng-app="app">
<head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    <meta charset=utf-8 />
    <title>JS Bin</title>
</head>
<body ng-controller="MyCtrl">
    {{serviceOutput}}
    <br/><br/>
    {{factoryOutput}}
    <br/><br/>
    {{providerOutput}}
    <script>
        var app = angular.module( 'app', [] );
        var MyFunc = function() {
            this.name = "default name";
            this.$get = function() {
                this.name = "new name"
                return "Hello from MyFunc.$get(). this.name = " + this.name;
            };
            return "Hello from MyFunc(). this.name = " + this.name;
        };
        // returns the actual function
        app.service( 'myService', MyFunc );
        // returns the function's return value
        app.factory( 'myFactory', MyFunc );
        // returns the output of the function's $get function
        app.provider( 'myProv', MyFunc );
        function MyCtrl( $scope, myService, myFactory, myProv ) {
            $scope.serviceOutput = "myService = " + myService;
            $scope.factoryOutput = "myFactory = " + myFactory;
            $scope.providerOutput = "myProvider = " + myProv;
        }
    </script>
</body>
</html>


Comme l'ont souligné à juste titre plusieurs personnes, une usine, un fournisseur, un service et même une valeur et une constante sont des versions identiques. Vous pouvez disséquer le plus général providerdans chacun d'eux. Ainsi:

Voici l'article de cette image:


C'est une partie très déroutante pour les débutants et j'ai essayé de le clarifier en termes simples

AngularJS Service: est utilisé pour partager des fonctions utilitaires avec la référence de service dans le contrôleur. Le service est de nature singleton, ainsi, pour un service, une seule instance est créée dans le navigateur et la même référence est utilisée sur toute la page.

Dans le service, nous créons des noms de fonction en tant que propriété avec cet objet.

AngularJS Factory: le but de Factory est également identique à celui de Service, mais dans ce cas, nous créons un nouvel objet et ajoutons des fonctions en tant que propriétés de cet objet.

Fournisseur AngularJS: l’objet de cette opération est à nouveau identique, mais le fournisseur donne le résultat de sa fonction $ get.

La définition et l'utilisation de Service, Factory et Fournisseur sont expliquées à l' http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider


Ma compréhension est très simple ci-dessous.

Usine: vous créez simplement un objet à l'intérieur de l'usine et vous le retournez.

Un service:

Vous avez juste une fonction standard qui utilise ce mot clé pour définir une fonction.

Fournisseur:

$getVous définissez un objet que vous pouvez utiliser pour obtenir l’objet qui renvoie les données.


JS Fiddle Demo

Exemple "Hello world" avec factory / service / provider :

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!";
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!";
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!";
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
</body>


J'ai remarqué quelque chose d'intéressant en jouant avec les fournisseurs.

La visibilité des produits injectables diffère pour les prestataires de services de celle des services et des usines. Si vous déclarez une constante AngularJS (par exemple, myApp.constant('a', 'Robert');), vous pouvez l'injecter dans des services, des usines et des fournisseurs.

Mais si vous déclarez une "valeur" AngularJS (par exemple., myApp.value('b', {name: 'Jones'});), Vous pouvez l'injecter dans des services et des usines, mais PAS dans la fonction de création de fournisseur. Vous pouvez cependant l'injecter dans la $getfonction que vous définissez pour votre fournisseur. Ceci est mentionné dans la documentation d'AngularJS, mais c'est facile à manquer. Vous pouvez le trouver sur la page% fourniture dans les sections consacrées aux méthodes value et constant.

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>

Il y a déjà de bonnes réponses, mais je veux juste partager celle-ci.

Tout d’abord: Provider est le moyen / la recette pour créer un service(objet singleton) qui doit être injecté par $ injector (comment AngulaJS traite le motif IoC).

Et valeur, usine, service et constante (4 façons) - le sucre syntaxique sur le moyen fournisseur / recepie.

Il y a une Service vs Factorypartie qui a été couvert: https://www.youtube.com/watch?v=BLzNCkPn3ao

Le service est tout à propos de newmot-clé qui, comme nous le savons, fait 4 choses:

  1. crée un nouvel objet
  2. le lie à son prototypeobjet
  3. se connecte contextàthis
  4. et retourne this

Et Factory est tout à propos de Factory Pattern - contient des fonctions qui renvoient des objets comme ce service.

  1. capacité à utiliser d'autres services (avoir des dépendances)
  2. initialisation du service
  3. initialisation retardée / lente

Et cette vidéo simple / courte: couvre également le fournisseur : https://www.youtube.com/watch?v=HvTZbQ_hUZY (vous pouvez voir comment ils vont de l’usine au fournisseur)

La recette du fournisseur est principalement utilisée dans la configuration de l'application, avant que l'application ne soit complètement lancée / initialisée.


Discutons les trois manières de gérer la logique métier dans AngularJS de manière simple: ( Inspiré du cours Coursera AngularJS de Yaakov )

SERVICE :

Syntaxe:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

Caractéristiques du service:

  1. Lazily Instancié : S'il n'est pas injecté, il ne sera jamais instancié. Donc, pour l'utiliser, il faudra l'injecter dans un module.
  2. Singleton : si injecté à plusieurs modules, tous n’auront accès qu’à une seule instance. C'est pourquoi il est très pratique de partager des données entre différents contrôleurs.

USINE

Voyons d'abord la syntaxe:

app.js :

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

Maintenant, en utilisant les deux ci-dessus dans le contrôleur:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

Caractéristiques de l'usine:

  1. Suit le modèle de conception d'usine. L'usine est un lieu central qui produit de nouveaux objets ou fonctions.
  2. Non seulement produit singleton, mais des services personnalisables.
  3. La .service()méthode est une fabrique qui produit toujours le même type de service, un singleton, sans aucun moyen facile de configurer son comportement. Cette .service()méthode est généralement utilisée comme raccourci pour quelque chose qui ne nécessite aucune configuration.

FOURNISSEUR

Regardons d'abord la syntaxe:

angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional

Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
  ServiceProvider.defaults.maxItems = 10; //some default value
}


ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
  //some methods
}

function ServiceProvider() {
  var provider = this;

  provider.defaults = {
    maxItems: 10
  };

  provider.$get = function () {
    var someList = new someListService(provider.defaults.maxItems);

    return someList;
  };
}

}

Caractéristiques du fournisseur:

  1. Fournisseur est la méthode la plus souple de création de services dans Angular.
  2. Non seulement nous pouvons créer une fabrique configurable de manière dynamique, mais au moment de l’utiliser, avec la méthode du fournisseur, nous pouvions personnaliser la fabrique une seule fois lors du démarrage de l’application entière.
  3. La fabrique peut ensuite être utilisée dans toute l'application avec des paramètres personnalisés. En d'autres termes, nous pouvons configurer cette usine avant le démarrage de l'application. En fait, dans la documentation angulaire, il est mentionné que la méthode du fournisseur est ce qui est réellement exécuté en arrière-plan lorsque nous configurons nos services avec l'une .serviceou l' autre des .factoryméthodes.
  4. Le $getest une fonction directement attachée à l'instance du fournisseur. Cette fonction est une fonction d' usine . En d'autres termes, c'est comme celui que nous utilisons pour fournir à la .factoryméthode. Dans cette fonction, nous créons notre propre service. Cette $getpropriété, c'est une fonction, est ce qui fait du fournisseur un fournisseur . AngularJS s'attend à ce que le fournisseur ait une propriété $ get dont la valeur est une fonction qu'Angular traitera comme une fonction d'usine. Mais ce qui rend toute l’installation de ce fournisseur très spéciale, c’est le fait que nous pouvons fournir un configobjet à l’intérieur du fournisseur de service, ce qui vient généralement avec des valeurs par défaut que nous pouvons écraser ultérieurement dans l’étape, où nous pouvons configurer toute l’application.

TL; DR

1) Lorsque vous utilisez une fabrique, vous créez un objet, lui ajoutez des propriétés, puis vous retournez ce même objet. Lorsque vous transmettez cette fabrique à votre contrôleur, les propriétés de l'objet sont désormais disponibles dans ce contrôleur via votre fabrique.

app.controller(‘myFactoryCtrl’, function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory(‘myFactory’, function(){
  var _artist = ‘Shakira’;
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2) Lorsque vous utilisez Service , AngularJS l’instancie en coulisse avec le mot-clé "new". A cause de cela, vous ajouterez des propriétés à 'this' et le service renverra 'this'. Lorsque vous transmettez le service à votre contrôleur, les propriétés de "ceci" seront désormais disponibles sur ce contrôleur via votre service.

app.controller(‘myServiceCtrl’, function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service(‘myService’, function(){
  var _artist = ‘Nelly’;
  this.getArtist = function(){
    return _artist;
  }
});



3) Les fournisseurs sont le seul service que vous pouvez transmettre à votre fonction .config (). Utilisez un fournisseur lorsque vous souhaitez fournir une configuration à l'échelle du module pour votre objet de service avant de le rendre disponible.

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = ‘This was set in config’;
});



Non TL; DR

1) usine
Les usines constituent le moyen le plus populaire de créer et de configurer un service. Il n'y a vraiment pas beaucoup plus que ce que dit le TL; DR. Vous créez simplement un objet, lui ajoutez des propriétés, puis vous retournez ce même objet. Ensuite, lorsque vous transmettez la fabrique à votre contrôleur, les propriétés de l'objet sont désormais disponibles dans ce contrôleur via votre fabrique. Un exemple plus complet est ci-dessous.

app.factory(‘myFactory’, function(){
  var service = {};
  return service;
});

Maintenant, toutes les propriétés que nous attachons à 'service' seront disponibles lorsque nous transmettrons 'myFactory' à notre contrôleur.

Ajoutons maintenant des variables "privées" à notre fonction de rappel. Celles-ci ne seront pas directement accessibles à partir du contrôleur, mais nous finirons par configurer des méthodes getter / setter sur 'service' afin de pouvoir modifier ces variables 'privées' si nécessaire.

app.factory(‘myFactory’, function($http, $q){
  var service = {};
  var baseUrl = ‘https://itunes.apple.com/search?term=’;
  var _artist = ‘’;
  var _finalUrl = ‘’;

  var makeUrl = function(){
   _artist = _artist.split(‘ ‘).join(‘+’);
    _finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
    return _finalUrl
  }

  return service;
});

Ici, vous remarquerez que nous n'attachons pas ces variables / fonctions à 'service'. Nous les créons simplement pour pouvoir les utiliser ou les modifier plus tard.

  • baseUrl est l'URL de base requise par l'API iTunes
  • _artist est l'artiste que nous souhaitons rechercher
  • _finalUrl est l'URL finale et entièrement construite vers laquelle nous allons appeler iTunes.
  • makeUrl est une fonction qui crée et renvoie notre URL conviviale pour iTunes.

Maintenant que nos variables et fonctions d'assistance / privées sont en place, ajoutons quelques propriétés à l'objet 'service'. Tout ce que nous mettons en "service" peut être utilisé directement dans n'importe quel contrôleur dans lequel nous transmettons "myFactory".

Nous allons créer les 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 renvoyer une promesse qui sera remplie 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 AngularJS, je vous recommande vivement de les approfondir.

SetArtist accepte un artiste et vous permet de le définir. 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 requête $ http avec notre URL finale, puis, puisque $ http renvoie une promesse, nous pouvons appeler .success ou .error après notre requête. Nous résolvons ensuite notre promesse avec les données iTunes ou nous la rejetons avec un message disant «Il y avait une erreur».

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

Maintenant, notre usine est terminée. Nous pouvons maintenant injecter «myFactory» dans n’importe quel contrôleur et nous pourrons ensuite appeler nos méthodes que nous avons attachées à notre objet service (setArtist, getArtist et callItunes).

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

Dans le contrôleur ci-dessus, nous injectons le service «myFactory». Nous définissons ensuite les propriétés de notre objet $ scope avec les données de 'myFactory'. Le seul code difficile ci-dessus est si vous n'avez jamais traité de promesses auparavant. Puisque callItunes renvoie une promesse, nous pouvons utiliser la méthode .then () et définir uniquement $ scope.data.artistData une fois que notre promesse est remplie avec les données iTunes. Vous remarquerez que notre contrôleur est très "mince" (c'est une bonne pratique de codage). Toutes nos données logiques et persistantes se trouvent dans notre service, pas dans notre contrôleur.

2) service
Peut-être que la chose la plus importante à savoir lors de la création d'un service est qu'il est instancié avec le mot-clé 'new'. Pour vous, gourous JavaScript, cela devrait vous donner un indice important sur la nature du code. Pour ceux d'entre vous qui ont une connaissance limitée de JavaScript ou pour ceux qui ne connaissent pas bien le «nouveau» mot clé, examinons quelques principes fondamentaux de JavaScript qui nous aideront éventuellement à comprendre la nature d'un service.

Pour vraiment voir les changements qui surviennent lorsque vous appelez une fonction avec le mot clé 'new', créons une fonction et appelez-la avec le mot clé 'new', puis montrons ce que l'interprète fait lorsqu'il voit le mot clé 'new'. Les résultats finaux seront les mêmes.

Commençons par créer notre constructeur.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

C'est une fonction constructeur typique de JavaScript. Désormais, chaque fois que nous appelons la fonction Person à l'aide du mot clé "new", "this" sera lié au nouvel objet créé.

Ajoutons maintenant une méthode sur le prototype de notre personne afin qu’elle soit disponible sur chaque instance de notre classe «personne».

Person.prototype.sayName = function(){
  alert(‘My name is ‘ + this.name);
}

Maintenant, comme nous mettons 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.

var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

En résumé, le code permettant de créer un constructeur Person, d’ajouter une fonction à son prototype, de créer une instance Person, puis d’appeler la fonction sur son prototype ressemble à ceci.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert(‘My name is ‘ + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

Examinons maintenant ce qui se passe réellement lorsque vous utilisez le mot-clé "nouveau" 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 s'il s'agissait d'un objet - c'est parce que c'est le cas. Donc, d’abord, nous savons que notre constructeur Person renvoie un objet, que nous le voyions ou non dans le code. Deuxièmement, nous savons que, puisque notre fonction sayName est située sur le prototype et non directement sur l'instance de personne, l'objet renvoyé par la fonction Person doit être délégué à son prototype lors de recherches en échec. En termes plus simples, lorsque nous appelons tyler.sayName (), l'interprète dit «OK, je vais regarder sur l'objet 'tyler» que nous venons de créer, localisez la fonction sayName, puis appelez-le. Attendez une minute, je ne le vois pas ici - je ne vois que le nom et l'âge, laissez-moi vérifier le prototype. Oui, on dirait que c'est sur le prototype, laissez-moi l'appeler. ”.

Vous trouverez ci-dessous un code indiquant comment vous pouvez penser à ce que le "nouveau" mot-clé fait réellement en JavaScript. C'est fondamentalement 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.

var Person = function(name, age){
  //The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets ‘this’ to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

Maintenant que vous avez cette connaissance de ce que le "nouveau" mot-clé fait vraiment en JavaScript, la création d'un service dans AngularJS 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 mot-clé 'nouveau' En combinant ces connaissances avec nos exemples ci-dessus, vous devez maintenant reconnaître que vous allez associer directement vos propriétés et méthodes à "this", qui seront ensuite renvoyées par le service lui-même. Jetons un coup d'oeil à ceci en action.

Contrairement à ce que nous avons fait à l’origine avec l’exemple Factory, nous n’avons pas besoin de créer un objet, mais de le renvoyer, car, comme cela a déjà été mentionné à maintes reprises, nous avons utilisé le mot clé 'new' pour que l’interprète crée cet objet et le délègue à c'est un prototype, puis retournez-le nous sans que nous ayons à faire le travail.

Tout d’abord, créons notre fonction «privée» et d’aide. 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 chaque ligne fait ici car je l'ai fait dans l'exemple d'usine. Si vous êtes confus, relisez l'exemple d'usine.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

Maintenant, nous allons attacher toutes les méthodes qui seront disponibles dans notre contrôleur à 'ceci'.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

Maintenant, comme dans notre usine, setArtist, getArtist et callItunes seront disponibles dans le contrôleur par lequel nous passerons à myService. Voici le contrôleur myService (qui est presque identique à notre contrôleur d’usine).

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

Comme je l'ai déjà mentionné, une fois que vous comprenez vraiment ce que fait le «nouveau», les services sont presque identiques aux usines AngularJS.

3) fournisseur

La chose la plus importante à retenir sur les fournisseurs est qu’ils sont le seul service que vous pouvez transférer dans la partie app.config de votre application. Cela revêt une importance capitale si vous devez modifier une partie de votre objet de service avant qu'il ne soit disponible partout ailleurs dans votre application. Bien que très similaires aux services / usines, il y a quelques différences dont nous discuterons.

Nous avons d’abord configuré notre fournisseur de la même manière que nous l’avons fait avec notre service et notre usine. Les variables ci-dessous sont notre fonction "privée" et d'assistance.

app.provider('myProvider', function(){
   var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below.
  this.thingFromConfig = ‘’;

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
}

* Encore une fois, si une partie du code ci-dessus est source de confusion, consultez la section Usine où j'explique ce que tout cela fait plus de détails.

Vous pouvez imaginer que les fournisseurs ont trois sections. La première section contient les variables / fonctions «privées» qui seront modifiées / définies ultérieurement (voir ci-dessus). La deuxième section contient les variables / fonctions qui seront disponibles dans votre fonction app.config et sont donc disponibles pour être modifiées avant d’être disponibles ailleurs (voir également ci-dessus). Il est important de noter que ces variables doivent être attachées au mot clé 'this'. Dans notre exemple, seul 'thingFromConfig' sera disponible pour être modifié dans le fichier app.config. La troisième section (illustrée ci-dessous) regroupe toutes les variables / fonctions qui seront disponibles dans votre contrôleur lorsque vous transmettez le service «myProvider» à ce contrôleur spécifique.

Lors de la création d'un service avec Fournisseur, les seules propriétés / méthodes disponibles dans votre contrôleur sont les propriétés / méthodes renvoyées par la fonction $ get (). Le code ci-dessous met $ get sur 'this' (qui, nous le savons, sera finalement renvoyé par cette fonction). Maintenant, cette fonction $ get renvoie toutes les méthodes / propriétés que nous voulons être disponibles dans le contrôleur. Voici un exemple de code.

this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }

Maintenant, le code complet du fournisseur ressemble à ceci

app.provider('myProvider', function(){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below
  this.thingFromConfig = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }
});

Désormais, comme dans notre usine et notre service, setArtist, getArtist et callItunes seront disponibles dans le contrôleur par lequel nous avons passé myProvider. Voici le contrôleur myProvider (qui est presque identique à notre contrôleur d’usine / service).

app.controller('myProviderCtrl', function($scope, myProvider){
  $scope.data = {};
  $scope.updateArtist = function(){
    myProvider.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myProvider.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }

  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

Comme mentionné précédemment, la création d'un service avec Provider permet de modifier certaines variables via la fonction app.config avant que l'objet final ne soit transmis au reste de l'application. Voyons un exemple de cela.

app.config(function(myProviderProvider){
  //Providers are the only service you can pass into app.config
  myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});

Vous pouvez maintenant voir comment 'thingFromConfig' est une chaîne vide dans notre fournisseur, mais lorsque cela apparaît dans le DOM, ce sera 'Cette phrase a été définie…'.


Une clarification supplémentaire est que les usines peuvent créer des fonctions / primitives alors que les services ne le peuvent pas. Découvrez ce jsFiddle basé sur Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .

La fabrique retourne une fonction qui peut être appelée:

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

La fabrique peut également renvoyer un objet avec une méthode pouvant être appelée:

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

Le service renvoie un objet avec une méthode pouvant être appelée:

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

Pour plus de détails, voir un article que j'ai écrit sur la différence: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


Sur la liste de diffusion AngularJS, j'ai trouvé un fil de discussion incroyable qui explique le service vs l'usine vs le fournisseur et leur utilisation par injection. Compiler les réponses:

Prestations de service

Syntaxe: module.service( 'serviceName', function );
Résultat: lors de la déclaration de serviceName en tant qu'argument injectable, une instance de la fonction vous sera fournie. En d'autres termes, new FunctionYouPassedToService() .

Des usines

Syntaxe: module.factory( 'factoryName', function );
Résultat: lors de la déclaration de factoryName en tant qu'argument injectable, vous recevrez la valeur renvoyée en appelant la référence de fonction transmise à module.factory .

Fournisseurs

Syntaxe: module.provider( 'providerName', function );
Résultat: lors de la déclaration de providerName en tant qu'argument injectable, vous recevrez (new ProviderFunction()).$get() . La fonction constructeur est instanciée avant l'appel de la méthode $ get - ProviderFunction est la référence de la fonction transmise à module.provider.

Les fournisseurs ont l’avantage de pouvoir être configurés pendant la phase de configuration du module.

Voir here pour le code fourni.

Voici une excellente explication supplémentaire de Misko:

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

Dans ce cas, l'injecteur renvoie simplement la valeur telle quelle. Mais que faire si vous voulez calculer la valeur? Ensuite, utilisez une usine

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

Donc, l’ factory est une fonction responsable de la création de la valeur. Notez que la fonction usine peut demander d'autres dépendances.

Mais que se passe-t-il si vous voulez être plus OO et avoir une classe appelée Greeter?

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

Ensuite, pour instancier, il faudrait écrire

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

Ensuite, nous pourrions demander 'greeter' dans le contrôleur comme celui-ci

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

Mais c'est beaucoup trop verbeux. Une manière plus courte d'écrire ceci serait provider.service('greeter', Greeter);

Mais si nous voulions configurer la classe Greeter avant l’injection? Ensuite, nous pourrions écrire

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

Ensuite, nous pouvons faire ceci:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

De plus, le service , l’ factory et la value sont tous dérivés du fournisseur.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};

Voici un exemple de code de plaque de grille que j'ai créé en tant que modèle de code pour la fabrique d'objets dans AngularjS. J'ai utilisé l'exemple de Car / CarFactory. Crée un code d'implémentation simple dans le contrôleur.

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

Voici un exemple plus simple. J'utilise quelques bibliothèques tierces qui attendent un objet "Position" exposant la latitude et la longitude, mais via des propriétés d'objet différentes. Je ne voulais pas pirater le code du vendeur, alors j'ai ajusté les objets "Position" que je faisais circuler.

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

;


Cette réponse aborde le sujet / la question

Comment Factory, Service et Constant - ne constituent-ils que du sucre syntaxique au-dessus d'une recette de fournisseur?

OU

comment l'usine, le service et les fournisseurs sont simailar en interne

essentiellement ce qui se passe est

Lorsque vous faites un factory()it définit que vous avez functionfourni le deuxième argument à provider $getet que vous le retournez ( provider(name, {$get:factoryFn })), tout ce que vous obtenez est, providermais il n'y a pas d'autre propriété / méthode que$get celle-ci provider(cela signifie que vous ne pouvez pas le configurer)

Code source de l'usine

function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
};

Lorsque vous faites un service()it, vous fournissez une fabrique () avec un functionqui injecte le constructor(retourne l'instance du constructeur que vous avez fourni dans votre service) et la retourne.

Code source du service

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
};

Donc, dans les deux cas, vous obtenez éventuellement un fournisseur $ get configuré pour votre fonction que vous avez fournie, mais vous pouvez donner quelque chose de plus que $ get comme vous pouvez le fournir à l’origine dans provider () pour le bloc de configuration


Après avoir lu tous ces articles, cela a créé plus de confusion pour moi.

  • L’injecteur utilise des recettes pour créer deux types d’objets: les services et les objets spéciaux
  • Il existe cinq types de recettes qui définissent comment créer des objets: Valeur, Usine, Service, Fournisseur et Constante.
  • Factory et Service sont les recettes les plus couramment utilisées. La seule différence entre eux est que la recette de service fonctionne mieux pour les objets d'un type personnalisé, tandis que la fabrique peut produire des primitives et des fonctions JavaScript.
  • La recette du fournisseur est le type de recette principale et toutes les autres ne sont que du sucre syntaxique.
  • Le fournisseur est le type de recette le plus complexe. Vous n'en avez pas besoin, sauf si vous créez un élément de code réutilisable nécessitant une configuration globale.
  • Tous les objets spéciaux, à l'exception du contrôleur, sont définis via des recettes d'usine.

Et pour les débutants, comprenez: - Cela ne corrigera peut-être pas le cas d’utilisation, mais en gros, c’est ce que nous utilisons pour ces trois cas.

  1. Si vous souhaitez utiliser un module angulaire, la fonction de configuration doit être créée en tant que fournisseur.

angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})

  1. Les intégrations d'appels Ajax ou de tiers doivent être un service .
  2. Pour les manipulations de données, créez-le en tant qu'usine

Pour les scénarios de base, usine et service se comportent de la même manière.


For short and simple explanation refer https://.com/a/26924234/5811973 .

For detailed explanation refer https://.com/a/15666049/5811973 .

Also from angularJs documentation:





angularjs dependency-injection angularjs-service angularjs-factory angularjs-provider