Question angular.service vs angular.factory


J'ai vu les deux angular.factory () et angular.service () utilisé pour déclarer des services; Cependant, je Impossible de trouver  angular.service n'importe où 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)?


1036
2018-01-14 18:36


origine


Réponses:


  angular.service('myService', myServiceFunction);
  angular.factory('myFactory', myFactoryFunction);

J'ai eu du mal à envelopper ma tête autour de ce concept jusqu'à ce que je me le dise de cette façon:

Un service: la fonction que vous écrivez sera Nouveau-ed:

  myInjectedService  <----  new myServiceFunction()

Usine: la fonction (constructeur) que vous écrivez sera invoqué:

  myInjectedFactory  <---  myFactoryFunction()

Ce que vous faites avec ça dépend de vous, mais il y a des modèles utiles ...

Tels que l'écriture d'un un service fonction pour exposer une API publique:

function myServiceFunction() {
  this.awesomeApi = function(optional) {
    // calculate some stuff
    return awesomeListOfValues;
  }
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();

Ou en utilisant un usine fonction pour exposer une API publique:

function myFactoryFunction() {
  var aPrivateVariable = "yay";

  function hello() {
    return "hello mars " + aPrivateVariable;
  }

  // expose a public API
  return {
    hello: hello
  };
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();

Ou en utilisant un usine fonction pour renvoyer un constructeur:

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

Lequel utiliser? ...

Vous pouvez accomplir la même chose avec les deux. Cependant, dans certains cas, le usine vous donne un peu plus de flexibilité pour créer un injectable avec une syntaxe plus simple. C'est parce 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:

var myShinyNewObject = new myInjectedService.myFunction()

ce qui est sans doute moins souhaitable que cela:

var myShinyNewObject = new myInjectedFactory();

(Mais vous devriez vous méfier de l'utilisation de ce type de modèle en premier lieu parce que NouveauLe fait de placer des objets dans vos contrôleurs crée des dépendances difficiles à suivre qui sont difficiles à simuler pour les tests. Mieux vaut avoir un service gérer une collection d'objets pour vous que d'utiliser new() rusé-naïf.)


Encore une chose, ils sont tous Singletons ...

Gardez également à l'esprit que dans les deux cas, angular vous aide à gérer un singleton. Peu importe où et combien de fois vous injectez votre service ou votre fonction, vous obtiendrez la même référence au même objet ou à la même fonction. (À l'exception de quand une usine renvoie simplement une valeur comme un nombre ou une chaîne, dans ce cas, vous aurez toujours la même valeur, mais pas une référence.)


1248
2018-02-20 06:46



Tout simplement ..

// Service
service = (a, b) => {
  a.lastName = b;
  return a;
};

// Factory
factory = (a, b) => Object.assign({}, a, { lastName: b });

const fullName = { firstName: 'john' };

// Service
const lastNameService = (a, b) => {
  a.lastName = b;
  return a;
};
console.log(lastNameService(fullName, 'doe'));

// Factory
const lastNameFactory = (a, b) => 
  Object.assign({}, a, { lastName: b })
console.log(lastNameFactory(fullName, 'doe'));


316
2018-01-08 02:05



Voici les principales différences:

Prestations de service

Syntaxe: module.service( 'serviceName', function );

Résultat: Lors de la déclaration de serviceName en tant qu'argument injectable, vous recevrez le instance d'une fonction transmis à module.service.

Utilisation: pourrait être utile pour partage des fonctions d'utilité qui sont utiles à invoquer en ajoutant simplement ( ) à la référence de la fonction injectée. Peut aussi être exécuté avec injectedArg.call( this ) ou similaire.

Des usines

Syntaxe: module.factory( 'factoryName', function );

Résultat: Lorsque vous déclarez factoryName comme argument injectable, vous recevrez le valeur renvoyée en appelant la référence de fonction transmis à module.factory.

Utilisation: Peut être utile pour renvoyer un 'classe' fonction qui peut ensuite être nouveau pour créer des instances.

Voici exemple en utilisant les services et l'usine. En savoir plus sur AngularJS Service vs Usine.

Vous pouvez également vérifier la Documentation AngularJS et une question similaire sur stackoverflow confus au sujet du service vs usine.


243
2018-04-09 23:18



TL; DR 

1) Lorsque vous utilisez un Usine vous créez un objet, lui ajoutez des propriétés, puis renvoyez le même objet. Lorsque vous passez cette usine dans votre contrôleur, ces propriétés sur l'objet seront désormais disponibles dans ce contrôleur via votre usine.

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 Un service, Angular l'instancie dans les coulisses avec le mot-clé 'new'. À cause de cela, vous ajouterez des propriétés à 'ceci' et le service retournera 'ceci'. Lorsque vous passez le service dans votre contrôleur, ces propriétés sur 'this' 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;
  }
});



Non TL; DR

1) Usine 
Les usines sont le moyen le plus populaire de créer et de configurer un service. Il n'y a vraiment pas beaucoup plus que ce que le TL, DR a dit. Vous venez de créer un objet, y ajouter des propriétés, puis retourner 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 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 passerons 'myFactory' dans notre contrôleur.

Ajoutons maintenant des variables 'privées' à notre fonction de rappel. Ceux-ci ne seront pas directement accessibles depuis le contrôleur, mais nous mettrons éventuellement en place des méthodes de getter / setter sur 'service' pour pouvoir modifier ces variables 'privées' en cas de besoin.

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 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 consulter
  • _finalUrl est l'URL finale et complète à laquelle nous ferons l'appel à iTunes makeUrl est une fonction qui va créer et retourner notre URL conviviale iTunes.

Maintenant que nos variables et fonctions auxiliaires / privées sont en place, ajoutons quelques propriétés à l'objet 'service'. Tout ce que nous mettons sur 'service', nous serons en mesure d'utiliser directement dans quel contrôleur nous passons 'myFactory' dans.

Nous allons créer des méthodes setArtist et getArtist qui retournent 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 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 vivement de faire un plongeon profond sur eux.

Au dessous de 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 crée un objet de promesse, fait une requête $ http avec notre URL finale, puis parce que $ http renvoie une promesse, nous sommes capables d'appeler .success ou .error après notre requête. Nous résolvons ensuite notre promesse avec les données iTunes, ou nous le 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 sommes maintenant capables d'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 dans le service 'myFactory'. Nous définissons ensuite des propriétés sur notre objet $ scope qui proviennent des données de 'myFactory'. Le seul code difficile ci-dessus est si vous n'avez jamais eu de promesses auparavant. Parce que callItunes renvoie une promesse, nous sommes en mesure d'utiliser la méthode .then () et seulement définir $ 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". Toutes nos données logiques et persistantes sont situées dans notre service, pas dans notre contrôleur.

2) Service 
Peut-être que la plus grande chose à savoir lors de la création d'un Service est qu'il est instancié avec le mot-clé «nouveau». Pour vous, les gourous JavaScript, cela devrait vous donner une grande indication 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 très bien le nouveau mot clé, passons en revue certains fondamentaux de JavaScript qui nous aideront éventuellement à comprendre la nature d'un Service.

Pour vraiment voir les changements qui se produisent lorsque vous invoquez une fonction avec le mot-clé 'new', créons une fonction et invoquons-la avec le mot-clé 'new', puis montrons ce que fait l'interpréteur quand il voit le mot-clé 'new'. Les résultats finaux seront les mêmes.

D'abord, créons notre constructeur.

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

C'est une fonction de constructeur JavaScript typique. Maintenant, chaque fois que nous invoquons la fonction Person en utilisant le mot clé 'new', 'this' sera lié à l'objet nouvellement créé.

Maintenant, ajoutons 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, parce que 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 de 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'

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.

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'

Voyons maintenant ce qui se passe réellement lorsque vous utilisez le mot-clé 'new' en JavaScript. La première chose que vous devriez remarquer est qu'après avoir utilisé 'new' dans notre exemple, nous sommes capables d'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 puissions le voir dans le code ou non. Deuxièmement, nous savons que parce que notre fonction sayName est située sur le prototype et pas directement sur l'instance de Person, l'objet renvoyé par la fonction Person doit être délégué à son prototype lors des recherches échouées. 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 la vois pas ici - tout ce que je vois c'est le nom et l'âge, laissez-moi vérifier le prototype. Ouais, on dirait que c'est sur le prototype, laissez-moi l'appeler. ".

Vous trouverez ci-dessous un code pour savoir ce que le mot-clé 'new' fait réellement en JavaScript. C'est fondamentalement un exemple de code du paragraphe ci-dessus. J'ai mis la 'vue de l'interprète' ou la façon dont l'interprète voit le code à l'intérieur des notes.

var Person = function(name, age){
  //The line below this creates an obj object 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;
}

Ayant maintenant cette connaissance de ce que le mot-clé 'new' fait vraiment dans JavaScript, la création d'un service dans Angular devrait être plus facile à comprendre.

La plus grande chose à 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 cette connaissance avec nos exemples ci-dessus, vous devriez maintenant reconnaître que vous allez attacher vos propriétés et méthodes directement à 'ceci' qui sera ensuite renvoyé par le Service lui-même. Jetons un coup d'oeil à ceci dans l'action.

Contrairement à ce que nous avions fait avec l'exemple Factory, nous n'avons pas besoin de créer un objet puis de retourner cet objet car, comme mentionné plusieurs fois auparavant, nous avons utilisé le mot clé 'new' pour que l'interpréteur crée cet objet. c'est un prototype, puis retournez-le pour nous sans que nous ayons à faire le travail.

Tout d'abord, créons notre fonction «privée» et assistante. 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 parce que je l'ai fait dans l'exemple de l'usine, si vous êtes confus, relisez l'exemple de l'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 nos 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, tout comme dans notre usine, setArtist, getArtist et callItunes seront disponibles dans n'importe quel contrôleur auquel nous transmettons myService. Voici le contrôleur myService (qui est presque exactement le même que 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 mentionné précédemment, une fois que vous comprenez vraiment ce que «nouveau» fait, les services sont presque identiques aux usines en Angular.


134
2018-05-14 16:14



L'indice est dans le nom

Les services et les usines sont similaires les uns aux autres. 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 pour implémenter un modèle de service

Un modèle de service est celui dans lequel votre application est divisée en unités de fonctionnalité logiquement cohérentes. Un exemple peut être un accesseur d'API ou un ensemble de logique métier.

Ceci est particulièrement important dans Angular parce que les modèles angulaires sont généralement juste des objets JSON tirés 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 comment parler à Github. Il connaît les urls et les méthodes. Nous pouvons l'injecter dans un contrôleur et générer et renvoyer une promesse.

(function() {
  var base = "https://api.github.com";

  angular.module('github', [])
    .service('githubService', function( $http ) {
      this.getEvents: function() {
        var url = [
          base,
          '/events',
          '?callback=JSON_CALLBACK'
        ].join('');
        return $http.jsonp(url);
      }
    });
  )();

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. Typiquement, nous pourrions l'utiliser pour construire des modèles. Voici une fabrique qui renvoie un constructeur Auteur:

angular.module('user', [])
  .factory('User', function($resource) {
    var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
    return $resource(url);
  })

Nous ferions usage de ceci comme:

angular.module('app', ['user'])
  .controller('authorController', function($scope, User) {
    $scope.user = new User();
  })

Notez que les usines retournent aussi des singletons.

Les usines peuvent renvoyer un constructeur

Parce qu'une usine renvoie simplement un objet, elle peut renvoyer n'importe quel type d'objet, y compris une fonction de constructeur, comme nous le verrons plus haut.

Les usines renvoient un objet; les services sont nouveaux

Une autre différence technique réside dans la manière dont les services et les usines sont composés. Une fonction de service sera créée pour générer l'objet. Une fonction d'usine sera appelée et retournera l'objet.

  • Les services sont des constructeurs nouveaux.
  • Les usines sont simplement appelées et retournent un objet.

Cela signifie que dans un service, nous ajoutons à "this" qui, dans le contexte d'un constructeur, pointera vers l'objet en construction.

Pour illustrer ceci, voici le même objet simple créé en utilisant un service et une usine:

angular.module('app', [])
  .service('helloService', function() {
    this.sayHello = function() {
      return "Hello!";
    }
  })
  .factory('helloFactory', function() {
    return {
      sayHello: function() {
        return "Hello!";
      }
    }
  });

33
2017-12-18 11:48



app.factory ('fn', fn) par rapport à 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é.

 //factory
 var obj = fn();
 return obj;

Avec les services, Angular appellera la fonction constructeur en appelant Nouveau. La fonction construite est mise en cache et injectée.

  //service
  var obj = new fn();
  return obj;

la mise en oeuvre

Les fabriques retournent généralement un littéral d'objet car la valeur de retour est ce qui est injecté dans les contrôleurs, les blocs d'exécution, les directives, etc.

  app.factory('fn', function(){
         var foo = 0;
         var bar = 0;
         function setFoo(val) {
               foo = val;
         }
         function setBar (val){
               bar = val;
         }
         return {
                setFoo: setFoo,
                serBar: setBar
         }
  });

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 faire référence à 'ceci' puisqu'elles ont été construites en utilisant 'nouveau'.

app.service('fn', function () {
         var foo = 0;
         var bar = 0;
         this.setFoo = function (val) {
               foo = val;
         }
         this.setBar = function (val){
               bar = val;
         }
});

Conclusion

Quand il s'agit d'utiliser des usines ou des services, ils sont tous les deux très similaires. Ils sont injectés dans un contrôleur, une directive, un bloc d'exécution, etc., et utilisés dans le code client à peu près de la même manière. Ils sont aussi deux singletons - signifiant que la même instance est partagée entre tous les endroits où le service / usine est injecté.

Alors, que devriez-vous préférer? L'un ou l'autre - ils sont si semblables que les différences sont triviales. Si vous choisissez l'un par rapport à l'autre, soyez simplement conscient de la façon dont ils sont construits, de sorte que vous puissiez les implémenter correctement.


23
2018-06-27 00:17



Toutes les réponses ici semblent être autour du service et de l'usine, et c'est valable puisque c'est ce qu'on demandait. Mais il est également important de garder à l'esprit qu'il existe plusieurs autres, y compris provider(), value(), et constant().

La clé à retenir est que chacun est un cas particulier de l'autre. Chaque cas spécial en bas de la chaîne vous permet de faire la même chose avec moins de code. Chacun ayant aussi une limitation supplémentaire.

Décider quand utiliser ce que 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:

enter image description here

Pour une ventilation complète étape par étape et une référence rapide de quand utiliser chacun, vous pouvez visiter l'article de blog où j'ai obtenu cette image de:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


23
2017-12-10 12:55