AngularJS: Service vs provider vs factory


3320

Quali sono le differenze tra un Service, Providere Factoryin AngularJS?


244
Ho scoperto che tutti i termini angolari erano intimidatori per i principianti. Abbiamo iniziato con questo cheatheet che era un po 'più facile da comprendere per i nostri programmatori durante l'apprendimento dell'angis demisx.github.io/angularjs/2014/09/14/… . Spero che questo aiuti anche la tua squadra.
Demisx,

7
Secondo me, il modo migliore per capire la differenza è usare la documentazione di Angular: docs.angularjs.org/guide/providers è estremamente ben spiegata e usa un esempio peculiare per aiutarti a capirla.
Rafael Merlin,

3
@ Blaise Grazie! Per il mio commento nel post, l'ho lasciato intenzionalmente, dal momento che il 99% dei casi d'uso della mia esperienza può essere gestito con successo tramite service.factory. Non volevo complicare ulteriormente questo argomento.
Demisx

3
Trovo che questa discussione sia anche molto utile stackoverflow.com/questions/18939709/…
Anand Gupta

3
Qui ci sono alcune buone risposte su comeservices,factorieseprovidersfunziona.
Mistalis,

Risposte:


2866

Dalla mailing list di AngularJS ho ricevuto un thread straordinario che spiega il servizio vs fabbrica vs fornitore e il loro utilizzo dell'iniezione. Compilare le risposte:

Servizi

Sintassi: module.service( 'serviceName', function );
Risultato: quando si dichiara serviceName come argomento iniettabile, verrà fornita un'istanza della funzione. In altre parole new FunctionYouPassedToService() .

fabbriche

Sintassi: module.factory( 'factoryName', function );
Risultato: quando si dichiara factoryName come argomento iniettabile, verrà fornito il valore restituito richiamando il riferimento della funzione passato a module.factory .

provider

Sintassi: module.provider( 'providerName', function );
Risultato: quando dichiari providerName come argomento iniettabile, ti verrà fornito (new ProviderFunction()).$get() . La funzione di costruzione viene istanziata prima che venga chiamato il metodo $ get - ProviderFunctionè il riferimento della funzione passato a module.provider.

I provider hanno il vantaggio di poter essere configurati durante la fase di configurazione del modulo.

Vedi qui per il codice fornito.

Ecco un'altra grande spiegazione di Misko:

provide.value('a', 123);

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

In questo caso l'iniettore restituisce semplicemente il valore così com'è. Ma cosa succede se si desidera calcolare il valore? Quindi utilizzare una fabbrica

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

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

Quindi factoryè una funzione che è responsabile della creazione del valore. Si noti che la funzione di fabbrica può richiedere altre dipendenze.

Ma cosa succede se vuoi essere più OO e avere una classe chiamata Greeter?

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

Quindi per creare un'istanza dovresti scrivere

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

Quindi potremmo chiedere "greeter" nel controller in questo modo

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

Ma è troppo prolisso. Un modo più breve per scrivere questo sarebbeprovider.service('greeter', Greeter);

E se volessimo configurare la Greeterclasse prima dell'iniezione? Quindi potremmo scrivere

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);
  };
});

Quindi possiamo farlo:

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

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

Come nota a margine, service, factory, e valuesono tutti derivati dallo provider.

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;
  });
};

58
Vedi anche stackoverflow.com/a/13763886/215945 che discute le differenze tra servizio e fabbrica.
Mark Rajcok,

3
Nella modifica 611 ho aggiunto l'uso di costanti e valori angolari. Per dimostrare le differenze dell'altro è già mostrato. jsbin.com/ohamub/611/edit
Nick

17
Sebbene venga chiamato un servizio creando un'istanza della funzione. In realtà viene creato una sola volta per iniettore, il che lo rende come singleton. docs.angularjs.org/guide/dev_guide.services.creating_services
angelokh

33
Questo esempio potrebbe essere incredibile se usasse un chiaro esempio pratico. Mi perdo cercando di capire quale sia il punto delle cose toEquale greeter.Greetsia. Perché non usare qualcosa di leggermente più reale e riconoscibile?
Kyle Pennell,

5
L'uso della funzione prevede () è una cattiva scelta per spiegare qualcosa. Usa il codice del mondo reale la prossima volta.
Craig,

812

JS Fiddle Demo

Esempio di "Hello world" con 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>


2
Non thiscambia il contesto nella $getfunzione? - non si fa più riferimento al provider istanziato in quella funzione.
Nate-Wilkins,

12
@Nate: in thisrealtà non cambia contesto, perché ciò che viene chiamato è new Provider(). $ Get (), dove si Providertrova la funzione app.provider. Vale a dire che $get()viene chiamato come metodo sulla costruzione Provider, quindi si thisfarà riferimento a Providercome suggerisce l'esempio.
Brandon,

1
@Brandon Ohh ok allora è un po 'pulito. A prima vista confuso - grazie per il chiarimento!
Nate-Wilkins,

3
Perché ottengo Unknown provider: helloWorldProvider <- helloWorldquando eseguo questo localmente? Commentandolo, stesso errore per gli altri 2 esempi. C'è qualche configurazione del provider nascosta? (Angular 1.0.8) - Trovato: stackoverflow.com/questions/12339272/…
Antoine

4
È il motivo per cui @Antoine ottiene l'errore "Unknown unknown: helloWorldProvider" perché nel tuo codice .config, usi 'helloWorldProvider', ma quando definisci il provider in myApp.provider ('helloWorld', function ()), usi 'Ciao mondo'? In altre parole, nel tuo codice di configurazione, come fa Angular a sapere che ti stai riferendo al fornitore helloWorld? Grazie
jmtoung

645

TL; DR

1) Quando si utilizza una Factory, si crea un oggetto, si aggiungono proprietà, quindi si restituisce lo stesso oggetto. Quando passi questa fabbrica nel tuo controller, quelle proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la tua fabbrica.

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) Quando si utilizza Service , AngularJS crea un'istanza dietro le quinte con la "nuova" parola chiave. Per questo motivo, aggiungi proprietà a "this" e il servizio restituirà "this". Quando si passa il servizio al controller, le proprietà su "this" saranno ora disponibili su quel controller tramite il servizio.

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

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



3) I provider sono l'unico servizio che puoi passare alla tua funzione .config (). Utilizzare un provider quando si desidera fornire una configurazione a livello di modulo per l'oggetto del servizio prima di renderlo disponibile.

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) Le Factory
Factory sono il modo più popolare per creare e configurare un servizio. Non c'è davvero molto di più di quello che ha detto il TL; DR. Basta creare un oggetto, aggiungere proprietà ad esso, quindi restituire lo stesso oggetto. Quindi quando passi la fabbrica nel tuo controller, quelle proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la tua fabbrica. Un esempio più ampio è di seguito.

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

Ora, qualunque proprietà attribuiamo al "servizio" sarà disponibile per noi quando passiamo "myFactory" nel nostro controller.

Ora aggiungiamo alcune variabili 'private' alla nostra funzione di callback. Questi non saranno direttamente accessibili dal controller, ma alla fine imposteremo alcuni metodi getter / setter su 'service' per essere in grado di modificare queste variabili 'private' quando necessario.

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;
});

Qui noterai che non stiamo associando tali variabili / funzioni al "servizio". Li stiamo semplicemente creando per usarli o modificarli in seguito.

  • baseUrl è l'URL di base richiesto dall'API di iTunes
  • _artista è l'artista che desideriamo cercare
  • _finalUrl è l'URL finale e completo a cui effettueremo la chiamata a iTunes
  • makeUrl è una funzione che creerà e restituirà il nostro URL amichevole di iTunes.

Ora che le nostre variabili e funzioni helper / private sono presenti, aggiungiamo alcune proprietà all'oggetto 'service'. Qualunque cosa mettiamo in "servizio" può essere utilizzata direttamente all'interno di qualsiasi controller in cui passiamo "myFactory".

Creeremo metodi setArtist e getArtist che semplicemente restituiscono o impostano l'artista. Creeremo anche un metodo che chiamerà l'API di iTunes con il nostro URL creato. Questo metodo restituirà una promessa che manterrà una volta che i dati sono tornati dall'API di iTunes. Se non hai avuto molta esperienza nell'uso delle promesse in AngularJS, ti consiglio vivamente di fare un tuffo profondo su di esse.

Sotto setArtist accetta un artista e ti consente di impostare l'artista. getArtist restituisce l'artista. callItunes prima chiama makeUrl () per creare l'URL che useremo con la nostra richiesta $ http. Quindi imposta un oggetto promessa, effettua una richiesta $ http con il nostro URL finale, quindi poiché $ http restituisce una promessa, siamo in grado di chiamare .success o .error dopo la nostra richiesta. Quindi risolviamo la nostra promessa con i dati di iTunes o la rifiutiamo con un messaggio che dice "Si è verificato un errore".

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;
});

Ora la nostra fabbrica è completa. Ora siamo in grado di iniettare "myFactory" in qualsiasi controller e potremo quindi chiamare i nostri metodi che abbiamo collegato al nostro oggetto di servizio (setArtist, getArtist e 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);
      })
  }
});

Nel controller sopra stiamo iniettando nel servizio "myFactory". Quindi impostiamo le proprietà sul nostro oggetto $ scope con i dati di 'myFactory'. L'unico codice di cui sopra è se non hai mai avuto a che fare con le promesse prima. Poiché callItunes sta restituendo una promessa, siamo in grado di utilizzare il metodo .then () e impostare $ scope.data.artistData solo dopo che la nostra promessa è stata rispettata con i dati di iTunes. Noterai che il nostro controller è molto "sottile" (questa è una buona pratica di codifica). Tutta la nostra logica e i dati persistenti si trovano nel nostro servizio, non nel nostro controller.

2) Servizio
Forse la cosa più importante da sapere quando si ha a che fare con la creazione di un servizio è che è istanziato con la "nuova" parola chiave. Per voi guru di JavaScript questo dovrebbe darvi un grande suggerimento sulla natura del codice. Per quelli di voi con un background limitato in JavaScript o per quelli che non hanno familiarità con ciò che effettivamente fa la "nuova" parola chiave, passiamo in rassegna alcuni fondamentali di JavaScript che alla fine ci aiuteranno a comprendere la natura di un Servizio.

Per vedere davvero le modifiche che si verificano quando invochi una funzione con la parola chiave "nuova", creiamo una funzione e invocala con la parola chiave "nuova", quindi mostriamo cosa fa l'interprete quando vede la parola chiave "nuova". I risultati finali saranno entrambi uguali.

Per prima cosa creiamo il nostro costruttore.

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

Questa è una tipica funzione di costruzione JavaScript. Ora, ogni volta che invochiamo la funzione Persona usando la parola chiave "new", "this" verrà associato all'oggetto appena creato.

Ora aggiungiamo un metodo sul prototipo della nostra Persona in modo che sia disponibile su ogni istanza della nostra "classe".

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

Ora, poiché mettiamo la funzione sayName sul prototipo, ogni istanza di Person sarà in grado di chiamare la funzione sayName per avvisare il nome dell'istanza.

Ora che abbiamo la nostra funzione di costruzione Person e la nostra funzione sayName sul suo prototipo, creiamo effettivamente un'istanza di Person quindi chiamiamo la funzione sayName.

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

Quindi tutti insieme il codice per creare un costruttore Person, aggiungere una funzione al suo prototipo, creare un'istanza Person e quindi chiamare la funzione sul suo prototipo appare così.

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’

Ora diamo un'occhiata a ciò che sta realmente accadendo quando usi la "nuova" parola chiave in JavaScript. La prima cosa che dovresti notare è che dopo aver usato 'new' nel nostro esempio, siamo in grado di chiamare un metodo (sayName) su 'tyler' proprio come se fosse un oggetto - è perché lo è. Quindi, per prima cosa, sappiamo che il nostro costruttore Person sta restituendo un oggetto, che possiamo vedere o meno nel codice. In secondo luogo, sappiamo che poiché la nostra funzione sayName si trova sul prototipo e non direttamente sull'istanza Person, l'oggetto che la funzione Person sta restituendo deve delegare al suo prototipo in caso di ricerche non riuscite. In termini più semplici, quando chiamiamo tyler.sayName () l'interprete dice “OK, cercherò l'oggetto 'tyler' che abbiamo appena creato, localizziamo la funzione sayName, quindi la chiamiamo. Aspetta un minuto, non lo vedo qui - tutto ciò che vedo è il nome e l'età, fammi controllare il prototipo. Sì, sembra che sia sul prototipo, lascia che lo chiami. ”.

Di seguito è riportato il codice su come pensare a ciò che la "nuova" parola chiave sta effettivamente facendo in JavaScript. È fondamentalmente un esempio di codice del paragrafo precedente. Ho inserito la "vista dell'interprete" o il modo in cui l'interprete vede il codice all'interno delle note.

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;
}

Ora, avendo questa conoscenza di ciò che fa la "nuova" parola chiave in JavaScript, la creazione di un servizio in AngularJS dovrebbe essere più facile da capire.

La cosa più importante da capire quando si crea un servizio è sapere che i servizi sono istanziati con la "nuova" parola chiave. Combinando questa conoscenza con i nostri esempi precedenti, ora dovresti riconoscere che alle tue proprietà e ai tuoi metodi collegherai direttamente "questo", che verrà quindi restituito dal Servizio stesso. Diamo un'occhiata a questo in azione.

A differenza di quello che abbiamo fatto inizialmente con l'esempio Factory, non abbiamo bisogno di creare un oggetto per restituirlo, perché, come menzionato molte volte in precedenza, abbiamo usato la parola chiave "new" in modo che l'interprete creerà quell'oggetto e ne faccia delegare è un prototipo, quindi restituiscilo per noi senza che dobbiamo fare il lavoro.

Per prima cosa, creiamo la nostra funzione "privata" e di supporto. Questo dovrebbe sembrare molto familiare poiché abbiamo fatto esattamente la stessa cosa con la nostra fabbrica. Non spiegherò cosa fa ogni riga qui perché l'ho fatto nell'esempio di fabbrica, se sei confuso, rileggi l'esempio di fabbrica.

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;
  }
});

Ora allegheremo tutti i nostri metodi che saranno disponibili nel nostro controller a "questo".

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;
  }

});

Proprio come nella nostra fabbrica, setArtist, getArtist e callItunes saranno disponibili in qualsiasi controller in cui passiamo myService. Ecco il controller myService (che è quasi identico al nostro controller di fabbrica).

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);
      })
  }
});

Come ho già detto prima, una volta capito davvero cosa fa il "nuovo", i Servizi sono quasi identici alle fabbriche di AngularJS.

3) Fornitore

La cosa più importante da ricordare sui provider è che sono l'unico servizio che puoi passare nella parte app.config della tua applicazione. Ciò è di enorme importanza se è necessario modificare una parte dell'oggetto del servizio prima che sia disponibile in qualsiasi altra parte dell'applicazione. Sebbene molto simile a Servizi / Fabbriche, ci sono alcune differenze di cui discuteremo.

Innanzitutto abbiamo impostato il nostro fornitore in modo analogo a quanto fatto con il nostro servizio e la nostra fabbrica. Le variabili seguenti sono la nostra funzione "privata" e di supporto.

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;
  }
}

* Ancora una volta se qualsiasi parte del codice sopra è confusa, controlla la sezione Factory dove spiego che cosa fa tutto maggiori dettagli.

Puoi pensare ai provider come a tre sezioni. La prima sezione sono le variabili / funzioni "private" che verranno modificate / impostate in seguito (mostrato sopra). La seconda sezione sono le variabili / funzioni che saranno disponibili nella funzione app.config e sono quindi disponibili per essere modificate prima di essere disponibili altrove (mostrate anche sopra). È importante notare che tali variabili devono essere associate alla parola chiave "this". Nel nostro esempio, solo "thingFromConfig" sarà disponibile per la modifica in app.config. La terza sezione (mostrata di seguito) sono tutte le variabili / funzioni che saranno disponibili nel controller quando si passa il servizio "myProvider" a quel controller specifico.

Quando si crea un servizio con Provider, le uniche proprietà / metodi che saranno disponibili nel controller sono quelle proprietà / metodi che vengono restituiti dalla funzione $ get (). Il codice seguente mette $ get su 'this' (che sappiamo che alla fine verrà restituito da quella funzione). Ora, quella funzione $ get restituisce tutti i metodi / proprietà che vogliamo essere disponibili nel controller. Ecco un esempio di codice.

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
    }
  }

Ora il codice completo del provider è simile al seguente

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
    }
  }
});

Proprio come nella nostra fabbrica e servizio, setArtist, getArtist e callItunes saranno disponibili in qualsiasi controller in cui passiamo myProvider. Ecco il controller myProvider (che è quasi identico al nostro controller di fabbrica / assistenza).

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;
});

Come accennato in precedenza, l'intero punto della creazione di un servizio con Provider è quello di poter modificare alcune variabili attraverso la funzione app.config prima che l'oggetto finale venga passato al resto dell'applicazione. Vediamo un esempio di questo.

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';
});

Ora puoi vedere come 'thingFromConfig' è una stringa vuota nel nostro provider, ma quando verrà visualizzata nel DOM, sarà "Questa frase è stata impostata ...".


11
L'unica parte che manca in questo eccellente articolo è i vantaggi relativi dell'utilizzo del servizio rispetto a una fabbrica; che è chiaramente spiegato nella risposta accettata da Lior
infinito

2
FWIW (forse non molto), ecco un blogger che mette in discussione Angular e non gli piace provider Provider codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
La battuta finale dei "guru JavaScript" era furba. : DI penso che questa risposta chiarisca molto le cose. Superbamente scritto.
amarmishra,

4
Il tuo TLDR ha bisogno di un TLDR.
JensB,

3
@JensB tl; dr - Learn React.
Tyler McGinnis,

512

Tutti i servizi sono singoli ; vengono istanziati una volta per app. Possono essere di qualsiasi tipo , che si tratti di una primitiva, oggetto letterale, funzione o anche un'istanza di un tipo personalizzato.

Il value, factory, service, constant, e providermetodi sono tutti i fornitori. Insegnano all'iniettore come creare un'istanza dei servizi.

Il più dettagliato, ma anche il più completo è una ricetta del Provider. I restanti quattro tipi di ricetta - Valore, Fabbrica, Servizio e Costante - sono solo zucchero sintattico in cima a una ricetta del fornitore .

  • La Ricetta Valore è il caso più semplice, in cui si crea un'istanza del Servizio e si fornisce il valore istanziato all'iniettore.
  • La ricetta Factory fornisce all'iniettore una funzione di fabbrica che chiama quando è necessario creare un'istanza del servizio. Quando viene chiamata, la funzione factory crea e restituisce l'istanza del servizio. Le dipendenze del servizio vengono inserite come argomenti delle funzioni. Quindi l'uso di questa ricetta aggiunge le seguenti abilità:
    • Possibilità di utilizzare altri servizi (hanno dipendenze)
    • Inizializzazione del servizio
    • Inizializzazione ritardata / lenta
  • La ricetta di servizio è quasi la stessa della ricetta di fabbrica, ma qui l'iniettore invoca un costruttore con il nuovo operatore anziché una funzione di fabbrica.
  • La ricetta del provider è generalmente eccessiva . Aggiunge un ulteriore livello di riferimento indiretto consentendoti di configurare la creazione della fabbrica.

    È necessario utilizzare la ricetta del provider solo quando si desidera esporre un'API per la configurazione a livello di applicazione che deve essere effettuata prima dell'avvio dell'applicazione. Questo di solito è interessante solo per i servizi riutilizzabili il cui comportamento potrebbe dover variare leggermente tra le applicazioni.

  • La ricetta Costante è proprio come la ricetta Valore, tranne per il fatto che consente di definire i servizi disponibili nella fase di configurazione . Prima dei servizi creati usando la ricetta Value. A differenza dei valori, non possono essere decorati con decorator.
Vedi la documentazione del provider .


2
Quindi servizio e fabbrica sono essenzialmente gli stessi? L'uso dell'uno non fornisce altro che una sintassi alternativa?
Matt,

2
@Matt, sì, il servizio è un modo conciso quando hai già una tua funzione che vuoi esporre come servizio. Da documenti: myApp.factory ('unicornLauncher', ["apiToken", funzione (apiToken) {return new UnicornLauncher (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
janek,

5
@joshperry Da principiante, ho cercato su Google la differenza tra servizio e fabbrica per un po '. Sono d'accordo che questa è la migliore risposta di sempre! Comprenderei il servizio come una classe di servizio (ad esempio classe encoder / decoder), che potrebbe avere alcune proprietà private. E la fabbrica fornisce una serie di metodi di supporto apolidi.
Stanleyxu2005,

3
Gli esempi di Yaa in altre risposte sopra non riescono a spiegare chiaramente la differenza fondamentale tra servizi e fornitori in b / n, che è ciò che viene iniettato nel momento in cui queste ricette vengono istanziate.
Ashish Singh,

223

Comprensione di AngularJS Factory, Service and Provider

Tutti questi sono usati per condividere oggetti singleton riutilizzabili. Aiuta a condividere il codice riutilizzabile attraverso la tua app / vari componenti / moduli.

Da Docs Service / Factory :

  • Pigramente istanziato : Angular crea un'istanza di un servizio / fabbrica solo quando un componente dell'applicazione dipende da esso.
  • Singletons : ogni componente dipendente da un servizio ottiene un riferimento alla singola istanza generata dalla factory di servizio.

Fabbrica

Una factory è una funzione in cui è possibile manipolare / aggiungere la logica prima di creare un oggetto, quindi l'oggetto appena creato viene restituito.

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

uso

Può essere solo una raccolta di funzioni come una classe. Quindi, può essere istanziato in controller diversi quando lo si inietta all'interno delle funzioni del controller / fabbrica / direttiva. Viene istanziato una sola volta per app.

Servizio

Basta guardare i servizi pensando al prototipo di array. Un servizio è una funzione che crea un'istanza di un nuovo oggetto utilizzando la parola chiave "new". È possibile aggiungere proprietà e funzioni a un oggetto servizio utilizzando la thisparola chiave. A differenza di una fabbrica, non restituisce nulla (restituisce un oggetto che contiene metodi / proprietà).

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

uso

Usalo quando devi condividere un singolo oggetto in tutta l'applicazione. Ad esempio, dettagli utente autenticati, metodi / dati condivisibili, funzioni di utilità ecc.

Provider

Un provider viene utilizzato per creare un oggetto servizio configurabile. È possibile configurare le impostazioni del servizio dalla funzione di configurazione. Restituisce un valore utilizzando la $get()funzione. La $getfunzione viene eseguita in fase di esecuzione in angolare.

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.
        };
    };
});

uso

Quando è necessario fornire una configurazione a livello di modulo per l'oggetto di servizio prima di renderlo disponibile, ad es. supponiamo di voler impostare l'URL dell'API in base al proprio ambiente come dev, stageoprod

NOTA

Solo il fornitore sarà disponibile in fase di configurazione angolare, mentre l'assistenza e la fabbrica no.

Spero che questo abbia chiarito la tua comprensione di Fabbrica, Servizio e Fornitore .


1
Cosa farei se volessi avere un servizio con una particolare interfaccia, ma avere due diverse implementazioni e iniettare ognuna in un controller ma legato a stati diversi usando ui-router? ad esempio, effettuare chiamate remote in uno stato, ma scrivere nella memoria locale anziché in un altro. I documenti del provider dicono di usare only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications, quindi non sembra possibile, giusto?
qix,

191

Per me, la rivelazione è arrivata quando mi sono reso conto che funzionano tutti allo stesso modo: eseguendo qualcosa una volta , memorizzando il valore che ottengono, e poi tossendo lo stesso valore memorizzato quando si fa riferimento attraverso l' iniezione di dipendenza .

Dì che abbiamo:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

La differenza tra i tre è che:

  1. aIl valore memorizzato viene eseguito fn.
  2. b'S valore memorizzato viene da newing fn.
  3. cIl valore memorizzato proviene dapprima ottenendo un'istanza tramite newing fn, quindi eseguendo un $getmetodo dell'istanza.

Ciò significa che c'è qualcosa come un oggetto cache all'interno di AngularJS, il cui valore di ogni iniezione viene assegnato una sola volta, quando sono stati iniettati la prima volta e dove:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

Questo è il motivo per cui usiamo thisnei servizi e definiamo un this.$getin provider.


2
Mi piace anche questa risposta di più. Il punto di tutti è fornire accesso a un oggetto ogni volta che è necessario tramite DI. Normalmente stai bene con factorys. L'unico motivo serviceper cui esistono sono linguaggi come CoffeeScript, TypeScript, ES6 ecc., Quindi puoi usare la loro sintassi di classe. È necessario providersolo se il modulo viene utilizzato in diverse applicazioni con impostazioni diverse utilizzando app.config(). Se il tuo servizio è un singolo singleton o è in grado di creare istanze di qualcosa dipende solo dalla tua implementazione.
Andreas Linnert,

137

Servizio vs fornitore vs fabbrica:

Sto cercando di mantenerlo semplice. Riguarda il concetto base di JavaScript.

Prima di tutto, parliamo di servizi in AngularJS!

Che cos'è il servizio: in AngularJS, il servizionon è altro che un oggetto JavaScript singleton in grado di memorizzare alcuni metodi o proprietà utili. Questo oggetto singleton viene creato su base ngApp (App angolare) ed è condiviso tra tutti i controller all'interno dell'app corrente. Quando Angularjs crea un'istanza di un oggetto servizio, registra questo oggetto servizio con un nome di servizio univoco. Quindi ogni volta che abbiamo bisogno dell'istanza del servizio, Angular cerca nel registro questo nome di servizio e restituisce il riferimento all'oggetto del servizio. In modo tale che possiamo invocare il metodo, accedere alle proprietà ecc. Sull'oggetto servizio. Potresti avere domande se puoi anche mettere proprietà, metodi sull'oggetto scope dei controller! Quindi perché hai bisogno di un oggetto di servizio? Risposte: i servizi sono condivisi tra più ambiti di controllo. Se si inseriscono alcune proprietà / metodi nell'oggetto ambito di un controller, questo sarà disponibile solo per l'ambito corrente.

Quindi, se ci sono tre ambiti del controller, sia controllerA, controllerB e controllerC, tutti condivideranno la stessa istanza del servizio.

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

Come creare un servizio?

AngularJS offre diversi metodi per registrare un servizio. Qui ci concentreremo su tre metodi factory (..), service (..), provider (..);

Utilizzare questo collegamento per riferimento al codice

Funzione di fabbrica:

Possiamo definire una funzione di fabbrica come di seguito.

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

AngularJS fornisce il metodo 'factory (' serviceName ', fnFactory)' che accetta due parametri, serviceName e una funzione JavaScript. Angular crea un'istanza di servizio richiamando la funzione fnFactory () come di seguito.

var serviceInstace = fnFactory();

La funzione passata può definire un oggetto e restituirlo. AngularJS memorizza semplicemente questo riferimento oggetto a una variabile che viene passata come primo argomento. Tutto ciò che viene restituito da fnFactory verrà associato a serviceInstance. Invece di restituire l'oggetto, possiamo anche restituire la funzione, i valori ecc., Qualunque cosa restituiremo, sarà disponibile per l'istanza del servizio.

Esempio:

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;
});

Funzione di servizio:

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

È un altro modo, possiamo registrare un servizio. L'unica differenza è il modo in cui AngularJS tenta di creare un'istanza dell'oggetto di servizio. Questa volta angolare usa la parola chiave "nuova" e chiama la funzione di costruzione come sotto.

var serviceInstance = new fnServiceConstructor();

Nella funzione di costruzione possiamo usare la parola chiave 'this' per aggiungere proprietà / metodi all'oggetto servizio. esempio:

//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);
  };
});

Funzione provider:

La funzione Provider () è un altro modo per creare servizi. Siamo interessati a creare un servizio che mostri all'utente solo un messaggio di saluto. Ma vogliamo anche fornire una funzionalità tale che l'utente possa impostare il proprio messaggio di saluto. In termini tecnici vogliamo creare servizi configurabili. Come possiamo farlo? Deve esserci un modo, in modo che l'app possa passare i propri messaggi di saluto personalizzati e Angularjs la renderebbe disponibile alla funzione factory / constructor che crea la nostra istanza di servizi. In tal caso, la funzione provider () esegue il lavoro. usando la funzione provider () possiamo creare servizi configurabili.

Siamo in grado di creare servizi configurabili utilizzando la sintassi del provider come indicato di seguito.

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

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

Come funziona la sintassi del provider internamente?

1.L'oggetto Provider viene creato utilizzando la funzione di costruzione definita nella funzione del nostro provider.

var serviceProvider = new serviceProviderConstructor();

2.La funzione che abbiamo passato in app.config (), viene eseguita. Questa si chiama fase di configurazione e qui abbiamo la possibilità di personalizzare il nostro servizio.

configureService(serviceProvider);

3.Finalmente l'istanza del servizio viene creata chiamando $ get method of serviceProvider.

serviceInstance = serviceProvider.$get()

Codice di esempio per la creazione del servizio utilizzando la sintassi di fornitura:

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 ?');
  }
);

Demo di lavoro

Sommario:


Factory utilizza una funzione factory che restituisce un'istanza di servizio. serviceInstance = fnFactory ();

Il servizio utilizza una funzione di costruzione e Angular invoca questa funzione di costruzione utilizzando la parola chiave "new" per la creazione dell'istanza del servizio. serviceInstance = new fnServiceConstructor ();

Il provider definisce una funzione providerConstructor, questa funzione providerConstructor definisce una funzione factory $ get . Chiamate angolari $ get () per creare l'oggetto di servizio. La sintassi del provider ha un ulteriore vantaggio di configurare l'oggetto del servizio prima che venga istanziato. serviceInstance = $ get ();



63

Fabbrica

Dai una funzione ad AngularJS, AngularJS memorizzerà nella cache e inietterà il valore di ritorno quando viene richiesto il factory.

Esempio:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

Uso:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

Servizio

Dai una funzione ad AngularJS, AngularJS chiamerà new per creare un'istanza. È l'istanza creata da AngularJS che verrà memorizzata nella cache e iniettata quando viene richiesto il servizio. Dal nuovo è stato utilizzato per creare un'istanza del servizio, la parola questo è valido e si riferisce all'istanza.

Esempio:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

Uso:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

Provider

Dai una funzione ad AngularJS e AngularJS chiamerà la sua $getfunzione. È il valore restituito dalla $getfunzione che verrà memorizzato nella cache e iniettato quando viene richiesto il servizio.

I provider ti consentono di configurare il provider prima che AngularJS chiami il $getmetodo per ottenere il iniettabile.

Esempio:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

Utilizzo (come iniettabile in un controller)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

Utilizzo (la configurazione del provider prima $getviene chiamata per creare il iniettabile)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});

56

Ho notato qualcosa di interessante giocando con i provider.

La visibilità degli iniettabili è diversa per i fornitori rispetto a quella per i servizi e le fabbriche. Se si dichiara una "costante" di AngularJS (ad esempio myApp.constant('a', 'Robert');), è possibile iniettarla in servizi, fabbriche e provider.

Ma se dichiari un "valore" di AngularJS (ad esempio., myApp.value('b', {name: 'Jones'});), Puoi inserirlo in servizi e fabbriche, ma NON nella funzione di creazione del provider. Tuttavia, è possibile iniettarlo nella $getfunzione definita per il proprio provider. Questo è menzionato nella documentazione di AngularJS, ma è facile da perdere. Puoi trovarlo nella pagina% fornire nelle sezioni sul valore e sui metodi costanti.

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>

45

Questa è una parte molto confusa per i principianti e ho cercato di chiarirlo in parole semplici

Servizio AngularJS: viene utilizzato per condividere le funzioni di utilità con il riferimento del servizio nel controller. Il servizio è di natura singleton, quindi per un servizio viene creata una sola istanza nel browser e lo stesso riferimento viene utilizzato in tutta la pagina.

Nel servizio, creiamo nomi di funzioni come proprietà con questo oggetto.

AngularJS Factory: lo scopo di Factory è lo stesso di Service, tuttavia in questo caso creiamo un nuovo oggetto e aggiungiamo funzioni come proprietà di questo oggetto e alla fine restituiamo questo oggetto.

Provider AngularJS: lo scopo è sempre lo stesso, tuttavia il Provider fornisce l'output della sua funzione $ get.

La definizione e l'utilizzo di Service, Factory e Provider sono spiegati su http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider


2
Factory e provider sono anche oggetti singleton? Qualche scanrio in cui le fabbriche sono consigliate rispetto ai servizi?
Sunil Garg,

34

Per me il modo migliore e più semplice di comprendere la differenza è:

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

In che modo AngularJS crea istanze di componenti particolari (semplificati):

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

// factory
var angularFactory = factory(injection);

Quindi, per il servizio, ciò che diventa il componente AngularJS è l'istanza dell'oggetto della classe che è rappresentata dalla funzione di dichiarazione del servizio. Per la fabbrica, è il risultato restituito dalla funzione di dichiarazione della fabbrica. La fabbrica può comportarsi come il servizio:

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

Il modo più semplice di pensare è il seguente:

  • Il servizio è un'istanza di oggetto singleton. Utilizzare i servizi se si desidera fornire un oggetto singleton per il proprio codice.
  • La fabbrica è una classe. Utilizzare le fabbriche se si desidera fornire classi personalizzate per il codice (non è possibile eseguire i servizi perché sono già istanziati).

L'esempio di "classe" di fabbrica è fornito nei commenti, oltre alla differenza del fornitore.


come può un servizio essere un singleton se viene istanziato ogni volta che viene utilizzato? riesco a farmi girare la testa ...
Joe,

Il servizio viene istanziato solo una volta durante la risoluzione delle dipendenze, quindi quando si richiede il servizio dall'iniettore, si ottiene sempre la stessa istanza. Può essere facilmente controllato qui: jsfiddle.net/l0co/sovtu55t/1 , eseguilo con la console. La console mostra che il servizio è istanziato una sola volta.
Lukasz Frankowski,

Oh, capisco. mi aspettavo di poter letteralmente new MyService()o qualcosa del genere :)
joe

33

Il mio chiarimento in merito:

Fondamentalmente tutti i tipi citati (servizio, fabbrica, fornitore, ecc.) Stanno solo creando e configurando variabili globali (che sono ovviamente globali per l'intera applicazione), proprio come lo erano le variabili globali vecchio stile.

Sebbene le variabili globali non siano consigliate, l'utilizzo reale di queste variabili globali è di fornire l' iniezione di dipendenza , passando la variabile al controller pertinente.

Esistono molti livelli di complicazioni nella creazione dei valori per le "variabili globali":

  1. Costante
    Definisce una costante effettiva che non deve essere modificata durante l'intera applicazione, proprio come le costanti in altre lingue (qualcosa che manca di JavaScript).
  2. Valore
    Questo è un valore o oggetto modificabile e funge da variabile globale, che può anche essere iniettato durante la creazione di altri servizi o fabbriche (vedere più avanti su questi). Tuttavia, deve essere un " valore letterale ", il che significa che si deve scrivere il valore reale e non è possibile utilizzare alcuna logica di calcolo o di programmazione (in altre parole 39 o myText o {prop: "valore"} sono OK, ma 2 +2 non lo è).
  3. Factory
    Un valore più generale, che può essere calcolato immediatamente. Funziona passando una funzione ad AngularJS con la logica necessaria per calcolare il valore e AngularJS lo esegue e salva il valore restituito nella variabile denominata.
    Si noti che è possibile restituire un oggetto (nel qual caso funzionerà in modo simile a un servizio ) o una funzione (che verrà salvata nella variabile come funzione di callback).
  4. Servizio
    Un servizio è una versione più ridotta di factory che è valida solo quando il valore è un oggetto e consente di scrivere qualsiasi logica direttamente nella funzione (come se fosse un costruttore), oltre a dichiarare e accedere le proprietà dell'oggetto usando questa parola chiave.
  5. Provider
    A differenza di un servizio che è una versione semplificata di factory , un provider è un modo più complesso, ma più flessibile di inizializzare le variabili "globali", con la massima flessibilità è l'opzione per impostare valori da app.config.
    Funziona come l'utilizzo di una combinazione di servizio e provider , passando al provider una funzione che ha proprietà dichiarate utilizzando questa parola chiave, che può essere utilizzata da app.config.
    Quindi deve avere una funzione $ .get separata che viene eseguita da AngularJS dopo aver impostato le proprietà sopra tramite il app.configfile, e questa funzione $ .get si comporta proprio come la factory sopra, in quanto il suo valore di ritorno viene utilizzato per inizializzare le variabili "globali".

26

La mia comprensione è molto semplice di seguito.

Factory: è sufficiente creare un oggetto all'interno della factory e restituirlo.

Servizio:

Hai solo una funzione standard che utilizza questa parola chiave per definire una funzione.

Provider:

C'è un $getoggetto che definisci e può essere usato per ottenere l'oggetto che restituisce dati.


Non hai confuso la fabbrica e il servizio? I servizi creano dove ritorna la fabbrica.
Flavien Volken,

Quando dichiari il nome del servizio come argomento iniettabile, ti verrà fornita un'istanza della funzione. In altre parole, nuovo FunctionYouPassedToService (). Questa istanza di oggetto diventa l'oggetto di servizio che AngularJS registra e inietta successivamente ad altri servizi / controller, se necessario. // factory Quando dichiari factoryname come argomento iniettabile, ti verrà fornito il valore che viene restituito invocando il riferimento della funzione passato a module.factory.
Sajan,

Va bene, quindi ... in angolare la fabbrica è un singleton in cui il "servizio" è in realtà una fabbrica (in termini di modelli di progettazione comuni)
Flavien Volken,

25

Riepilogo da documenti angolari :

  • Esistono cinque tipi di ricetta che definiscono come creare oggetti: Valore , Fabbrica , Servizio , Fornitore e Costante .
  • Fabbrica e assistenza sono le ricette più comunemente utilizzate. L'unica differenza è che la ricetta di servizio funziona meglio per oggetti di tipo personalizzato, mentre Factory può produrre primitive e funzioni JavaScript.
  • La ricetta del provider è il tipo di ricetta principale e tutti gli altri sono solo zucchero sintattico.
  • Il provider è il tipo di ricetta più complesso. Non ti serve se non stai costruendo un pezzo di codice riutilizzabile che necessita di una configurazione globale.

inserisci qui la descrizione dell'immagine


Migliori risposte da SO:

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


20

Tutte le buone risposte già. Vorrei aggiungere altri punti su Service e Factory . Insieme alla differenza tra servizio / fabbrica. E si possono anche avere domande come:

  1. Dovrei usare il servizio o la fabbrica? Qual è la differenza?
  2. Hanno lo stesso comportamento o hanno lo stesso comportamento?

Cominciamo con la differenza tra servizio e fabbrica:

  1. Entrambi sono Singleton : ogni volta che Angular li trova come dipendenza per la prima volta, crea una singola istanza di servizio / fabbrica. Una volta creata l'istanza, la stessa istanza viene utilizzata per sempre.

  2. Può essere utilizzato per modellare un oggetto con comportamento : possono avere entrambi metodi, variabili di stato interne e così via. Anche se il modo in cui scrivi quel codice sarà diverso.

Servizi:

Un servizio è una funzione di costruzione e Angular lo creerà un'istanza chiamando new yourServiceName(). Questo significa un paio di cose.

  1. Le funzioni e le variabili di istanza saranno proprietà di this.
  2. Non è necessario restituire un valore. Quando Angular chiama new yourServiceName(), riceverà l' thisoggetto con tutte le proprietà che ci metti sopra.

Esempio di esempio:

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

Quando Angular inietta questo MyServiceservizio in un controller che dipende da esso, quel controller otterrà un servizio su MyServicecui può chiamare funzioni, ad esempio MyService.aServiceMethod ().

Stai attento conthis :

Poiché il servizio costruito è un oggetto, i metodi al suo interno possono fare riferimento a questo quando vengono chiamati:

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++;
  };
});

Potresti essere tentato di chiamare ScoreKeeper.setScoreuna catena di promesse, ad esempio se hai inizializzato il punteggio afferrandolo dal server: $http.get('/score').then(ScoreKeeper.setScore).il problema è che ScoreKeeper.setScoreverrà chiamato con thisassociato nulle otterrai errori. Il modo migliore sarebbe $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Sia che tu scelga di utilizzarlo nei tuoi metodi di servizio o meno, fai attenzione a come li chiami.

Restituzione di un valore da aService :

A causa del funzionamento dei costruttori JavaScript, se si restituisce un valore complesso (i.e., an Object)da una constructorfunzione, il chiamante otterrà quell'oggetto anziché questa istanza.

Ciò significa che puoi sostanzialmente copiare e incollare l'esempio di fabbrica dal basso, sostituirlo factorycon servicee funzionerà:

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

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

Quindi, quando Angular costruisce il tuo servizio con il nuovo MyService (), otterrà quell'oggetto api anziché l'istanza di MyService.

Questo è il comportamento per qualsiasi valore complesso (oggetti, funzioni) ma non per tipi primitivi.

fabbriche:

Una factory è una semplice vecchia funzione che restituisce un valore. Il valore di ritorno è ciò che viene iniettato in cose che dipendono dalla fabbrica. Un tipico modello di fabbrica in Angolare è di restituire un oggetto con funzioni come proprietà, come questa:

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

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

  return api;
});

Il valore iniettato per una dipendenza factory è il valore restituito dalla factory e non deve essere un oggetto. Potrebbe essere una funzione

Risposte per le domande precedenti 1 e 2:

Per la maggior parte, basta usare le fabbriche per tutto. Il loro comportamento è più facile da capire. Non c'è scelta da fare se restituire un valore o meno, e inoltre, nessun bug da introdurre se si fa la cosa sbagliata.

Mi riferisco comunque a loro come "servizi" quando sto parlando di iniettarli come dipendenze, comunque.

Il comportamento di servizio / fabbrica è molto simile e alcune persone diranno che uno dei due va bene. È un po 'vero, ma trovo più facile seguire i consigli della guida di stile di John Papa e limitarmi a seguire le fabbriche. **


16

Un ulteriore chiarimento è che le fabbriche possono creare funzioni / primitive, mentre i servizi non possono. Dai un'occhiata a questo jsFiddle basato su Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .

La fabbrica restituisce una funzione che può essere invocata:

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

Il factory può anche restituire un oggetto con un metodo che può essere invocato:

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

Il servizio restituisce un oggetto con un metodo che può essere invocato:

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

Per maggiori dettagli, vedi un post che ho scritto sulla differenza: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


16

Ci sono già buone risposte, ma voglio solo condividere questa.

Prima di tutto: il provider è il modo / la ricetta per creare un service(oggetto singleton) che supponga di essere iniettato da $ injector (come AngulaJS procede secondo il modello IoC).

E Valore, Fabbrica, servizio e Constant (4 modi) - lo zucchero sintattico sopra Provider modo / recepie.

C'è una Service vs Factoryparte è stata coperta: https://www.youtube.com/watch?v=BLzNCkPn3ao

Il servizio è tutto sulla newparola chiave in realtà che come sappiamo fa 4 cose:

  1. crea un oggetto nuovo di zecca
  2. lo collega al suo prototypeoggetto
  3. si connette contextathis
  4. e ritorna this

E Factory è tutto basato su Pattern di fabbrica: contiene funzioni che restituiscono oggetti come quel servizio.

  1. capacità di usare altri servizi (avere dipendenze)
  2. inizializzazione del servizio
  3. inizializzazione ritardata / lenta

E questo semplice / breve video: copre anche il provider : https://www.youtube.com/watch?v=HvTZbQ_hUZY (qui puoi vedere come vanno dalla fabbrica al fornitore)

La ricetta del provider viene utilizzata principalmente nella configurazione dell'app, prima che l'app venga completamente avviata / inizializzata.


14

Dopo aver letto tutti questi post ha creato più confusione per me .. Ma comunque tutto è utile informazioni .. finalmente ho trovato la seguente tabella che fornirà informazioni con un semplice confronto

  • L'iniettore utilizza ricette per creare due tipi di oggetti: servizi e oggetti per scopi speciali
  • Esistono cinque tipi di ricetta che definiscono come creare oggetti: Valore, Fabbrica, Servizio, Fornitore e Costante.
  • Fabbrica e assistenza sono le ricette più utilizzate. L'unica differenza è che la ricetta di servizio funziona meglio per oggetti di tipo personalizzato, mentre Factory può produrre primitive e funzioni JavaScript.
  • La ricetta del provider è il tipo di ricetta principale e tutti gli altri sono solo zucchero sintattico.
  • Il provider è il tipo di ricetta più complesso. Non ti serve se non stai costruendo un pezzo di codice riutilizzabile che necessita di una configurazione globale.
  • Tutti gli oggetti per scopi speciali, ad eccezione del controller, sono definiti tramite ricette di fabbrica.

inserisci qui la descrizione dell'immagine

E per i principianti capire: - Questo potrebbe non correggere il caso d'uso, ma ad alto livello questo è ciò che serve per questi tre.

  1. Se si desidera utilizzare la funzione di configurazione del modulo angolare deve essere creata come provider

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

  1. La chiamata Ajax o le integrazioni di terze parti devono essere di servizio .
  2. Per manipolazioni dei dati crearlo come factory

Per scenari di base, la fabbrica e l'assistenza si comportano allo stesso modo.


13

Ecco un po 'di codice broilerplate che ho creato come modello di codice per la fabbrica di oggetti in AngularjS. Ho usato un Car / CarFactory come esempio per illustrare. Rende semplice il codice di implementazione nel controller.

     <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>

Ecco un esempio più semplice. Sto usando alcune librerie di terze parti che prevedono un oggetto "Position" che espone latitudine e longitudine, ma tramite diverse proprietà dell'oggetto. Non volevo hackerare il codice del fornitore, quindi ho modificato gli oggetti "Posizione" che stavo passando.

    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

;


12

Usando come riferimento questa pagina e la documentazione (che sembra essere notevolmente migliorata dall'ultima volta che ho guardato), ho messo insieme la seguente demo del mondo reale (-ish) che utilizza 4 dei 5 tipi di provider; Valore, costante, fabbrica e fornitore completo.

HTML:

<div ng-controller="mainCtrl as main">
    <h1>{{main.title}}*</h1>
    <h2>{{main.strapline}}</h2>
    <p>Earn {{main.earn}} per click</p>
    <p>You've earned {{main.earned}} by clicking!</p>
    <button ng-click="main.handleClick()">Click me to earn</button>
    <small>* Not actual money</small>
</div>

App

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

// A CONSTANT is not going to change
app.constant('range', 100);

// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');

// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
    // Get a random number within the range defined in our CONSTANT
    return Math.random() * range;
});

// A PROVIDER, must return a custom type which implements the functionality 
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will 
// instantiate and return.
var Money = function(locale) {

    // Depending on locale string set during config phase, we'll
    // use different symbols and positioning for any values we 
    // need to display as currency
    this.settings = {
        uk: {
            front: true,
            currency: '£',
            thousand: ',',
            decimal: '.'
        },
        eu: {
            front: false,
            currency: '€',
            thousand: '.',
            decimal: ','
        }
    };

    this.locale = locale;
};

// Return a monetary value with currency symbol and placement, and decimal 
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {

    var settings = this.settings[this.locale],
        decimalIndex, converted;

    converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);

    decimalIndex = converted.length - 3;

    converted = converted.substr(0, decimalIndex) +
        settings.decimal +
        converted.substr(decimalIndex + 1);    

    converted = settings.front ?
            settings.currency + converted : 
            converted + settings.currency; 

    return converted;   
};

// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
   return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};

// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {

    var locale;

    // Function called by the config to set up the provider
    this.setLocale = function(value) {
        locale = value;   
    };

    // All providers need to implement a $get method which returns
    // an instance of the custom class which constitutes the service
    this.$get = function moneyFactory() {
        return new Money(locale);
    };
});

// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
    moneyProvider.setLocale('uk');
    //moneyProvider.setLocale('eu'); 
}]);

// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {

    // Plain old VALUE(s)
    this.title = title;
    this.strapline = strapline;

    this.count = 0;

    // Compute values using our money provider    
    this.earn = money.convertValue(random); // random is computed @ runtime
    this.earned = money.convertValue(0);

    this.handleClick = function() { 
        this.count ++;
        this.earned = money.convertValue(random * this.count);
    };
});

Demo funzionante .


12

Questa risposta affronta l'argomento / domanda

come Factory, Service e Constant - sono solo zucchero sintattico in cima alla ricetta di un fornitore?

O

come fabbrica, servizio e fornitori sono simili internamente

fondamentalmente quello che succede è

Quando effettui un factory()set impostato functionnel secondo argomento fornito dal provider $gete lo restituisci ( provider(name, {$get:factoryFn })), tutto ciò che ottieni è providerma non esiste alcuna proprietà / metodo diverso da$get quello provider(significa che non puoi configurarlo)

Codice sorgente di fabbrica

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

Quando si effettua un service()ritorno, si fornisce a factory () un carattere functionche inietta il constructor(restituisce l'istanza del costruttore fornita nel servizio) e lo restituisce

Codice sorgente del servizio

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

Quindi sostanzialmente in entrambi i casi alla fine ottieni un $ provider impostato sulla tua funzione che hai fornito, ma puoi dare qualcosa in più di $ get come puoi inizialmente fornire in provider () per il blocco di configurazione


11

Conosco molte risposte eccellenti, ma devo condividere la mia esperienza di utilizzo di
1. serviceper la maggior parte dei casi di default
2. factoryutilizzato per creare il servizio di quell'istanza specifica

// 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){ ...
    }       
}
})();

e usando:

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;
... 

10

Poco in ritardo alla festa. Ma ho pensato che questo fosse più utile per chi vorrebbe imparare (o avere chiarezza) sullo sviluppo dei servizi personalizzati di Angular JS usando le metodologie di fabbrica, di servizio e dei fornitori.

Mi sono imbattuto in questo video che spiega chiaramente le metodologie di fabbrica, di servizio e dei fornitori per lo sviluppo dei servizi personalizzati AngularJS:

https://www.youtube.com/watch?v=oUXku28ex-M

Codice sorgente: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

Il codice pubblicato qui viene copiato direttamente dalla fonte di cui sopra, a beneficio dei lettori.

Il codice per il servizio personalizzato basato su "factory" è il seguente (che si accompagna alle versioni sync e async insieme alla chiamata del servizio http):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
  function($scope, calcFactory) {
    $scope.a = 10;
    $scope.b = 20;

    $scope.doSum = function() {
      //$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
      calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
        $scope.sum = r;
      });
    };

  }
]);

app.factory('calcFactory', ['$http', '$log',
  function($http, $log) {
    $log.log("instantiating calcFactory..");
    var oCalcService = {};

    //oCalcService.getSum = function(a,b){
    //	return parseInt(a) + parseInt(b);
    //};

    //oCalcService.getSum = function(a, b, cb){
    //	var s = parseInt(a) + parseInt(b);
    //	cb(s);
    //};

    oCalcService.getSum = function(a, b, cb) { //using http service

      $http({
        url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
        method: 'GET'
      }).then(function(resp) {
        $log.log(resp.data);
        cb(resp.data);
      }, function(resp) {
        $log.error("ERROR occurred");
      });
    };

    return oCalcService;
  }
]);

Il codice per la metodologia di "servizio" per i servizi personalizzati (è abbastanza simile a "factory", ma diverso dal punto di vista della sintassi):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.service('calcService', ['$http', '$log', function($http, $log){
	$log.log("instantiating calcService..");
	
	//this.getSum = function(a,b){
	//	return parseInt(a) + parseInt(b);
	//};

	//this.getSum = function(a, b, cb){
	//	var s = parseInt(a) + parseInt(b);
	//	cb(s);
	//};

	this.getSum = function(a, b, cb){
		$http({
			url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
			method: 'GET'
		}).then(function(resp){
			$log.log(resp.data);
			cb(resp.data);
		},function(resp){
			$log.error("ERROR occurred");
		});
	};

}]);

Il codice per la metodologia "provider" per i servizi personalizzati (questo è necessario, se si desidera sviluppare un servizio che potrebbe essere configurato):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.provider('calcService', function(){

	var baseUrl = '';

	this.config = function(url){
		baseUrl = url;
	};

	this.$get = ['$log', '$http', function($log, $http){
		$log.log("instantiating calcService...")
		var oCalcService = {};

		//oCalcService.getSum = function(a,b){
		//	return parseInt(a) + parseInt(b);
		//};

		//oCalcService.getSum = function(a, b, cb){
		//	var s = parseInt(a) + parseInt(b);
		//	cb(s);	
		//};

		oCalcService.getSum = function(a, b, cb){

			$http({
				url: baseUrl + '/Sum?a=' + a + '&b=' + b,
				method: 'GET'
			}).then(function(resp){
				$log.log(resp.data);
				cb(resp.data);
			},function(resp){
				$log.error("ERROR occurred");
			});
		};		

		return oCalcService;
	}];

});

app.config(['calcServiceProvider', function(calcServiceProvider){
	calcServiceProvider.config("http://localhost:4467");
}]);

Infine, l'interfaccia utente che funziona con uno dei servizi di cui sopra:

<html>
<head>
	<title></title>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
	<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
	<div ng-controller="emp">
		<div>
			Value of a is {{a}},
			but you can change
			<input type=text ng-model="a" /> <br>

			Value of b is {{b}},
			but you can change
			<input type=text ng-model="b" /> <br>

		</div>
		Sum = {{sum}}<br>
		<button ng-click="doSum()">Calculate</button>
	</div>
</body>
</html>


10

Solo per chiarire le cose, dalla fonte AngularJS, puoi vedere un servizio che chiama semplicemente la funzione factory che a sua volta chiama la funzione provider:

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

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

9

Discutiamo i tre modi di gestire la logica aziendale in AngularJS in modo semplice: ( Ispirato al corso Coursera AngularJS di Yaakov )

SERVIZIO :

Sintassi:

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>

Caratteristiche del servizio:

  1. Pigramente istanziato : se non viene iniettato, non verrà mai istanziato. Quindi per usarlo dovrà iniettarlo in un modulo.
  2. Singleton : se iniettato in più moduli, tutti avranno accesso a una sola istanza particolare. Ecco perché è molto comodo condividere i dati tra diversi controller.

FABBRICA

Per prima cosa diamo un'occhiata alla sintassi:

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;
}

Ora usando i due sopra nel controller:

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

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

Caratteristiche di fabbrica:

  1. Segue il modello di progettazione di fabbrica. La fabbrica è un luogo centrale che produce nuovi oggetti o funzioni.
  2. Non solo produce singleton, ma servizi personalizzabili.
  3. Il .service()metodo è una factory che produce sempre lo stesso tipo di servizio, che è un singleton e senza alcun modo semplice per configurarne il comportamento. Questo .service()metodo viene solitamente utilizzato come scorciatoia per qualcosa che non richiede alcuna configurazione.

PROVIDER

Diamo di nuovo un'occhiata alla sintassi prima:

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;
  };
}

}

Caratteristiche del provider:

  1. Il provider è il metodo più flessibile per creare servizi in angolare.
  2. Non solo siamo in grado di creare una factory configurabile dinamicamente, ma al momento dell'utilizzo della factory, con il metodo del provider, potremmo configurare la factory solo una volta al bootstrap dell'intera nostra applicazione.
  3. La fabbrica può quindi essere utilizzata in tutta l'applicazione con impostazioni personalizzate. In altre parole, possiamo configurare questa fabbrica prima dell'avvio dell'applicazione. Infatti nella documentazione angolare si dice che il metodo del provider è ciò che viene effettivamente eseguito dietro le quinte quando configuriamo i nostri servizi con uno .serviceo.factory metodi.
  4. La $getè una funzione che è direttamente collegato alla istanza del provider. Quella funzione è una funzione di fabbrica . In altre parole, è proprio come quello che usiamo per fornire al .factorymetodo. In quella funzione, creiamo il nostro servizio. Questa $getproprietà, questa è una funzione, è ciò che rende il provider un provider . AngularJS prevede che il provider disponga di una proprietà $ get il cui valore è una funzione che Angular considererà come una funzione factory. Ma ciò che rende molto speciale questa configurazione di tutto il provider, è il fatto che possiamo fornire alcuni configoggetti all'interno del fornitore di servizi e che di solito viene fornito con impostazioni predefinite che possiamo successivamente sovrascrivere nel passaggio, in cui possiamo configurare l'intera applicazione.

7

Fabbrica: la fabbrica in cui crei effettivamente un oggetto all'interno della fabbrica e lo restituisci.
servizio: il servizio che hai appena una funzione standard che utilizza questa parola chiave per definire la funzione.
provider: il provider ha $ get che definisci e può essere utilizzato per ottenere l'oggetto che restituisce i dati.


7

Essenzialmente, Provider, Factory e Service sono tutti servizi. Una Factory è un caso speciale di un Servizio quando tutto ciò che serve è una funzione $ get (), che consente di scriverlo con meno codice.

Le principali differenze tra servizi, fabbriche e fornitori sono le loro complessità. I servizi sono la forma più semplice, le fabbriche sono un po 'più robuste e i provider sono configurabili in fase di esecuzione.

Ecco un riepilogo di quando utilizzare ciascuno:

Factory : il valore fornito deve essere calcolato sulla base di altri dati.

Servizio : stai restituendo un oggetto con metodi.

Provider : vuoi essere in grado di configurare, durante la fase di configurazione, l'oggetto che verrà creato prima della sua creazione. Utilizzare il provider principalmente nella configurazione dell'app, prima che l'app sia stata inizializzata completamente.


ehm. Valore, fabbrica, servizio e costante: sono solo zucchero sintattico in cima alla ricetta di un fornitore. Documenti Angularjs - provider
Sudarshan_SMD

sì, sono d'accordo, ora con Angular 4 non abbiamo più questo mal di testa
eGhoul,

4

1.I servizi sono oggetti singleton che vengono creati quando necessario e non vengono mai ripuliti fino alla fine del ciclo di vita dell'applicazione (alla chiusura del browser). I controller vengono distrutti e ripuliti quando non sono più necessari.

2.Il modo più semplice per creare un servizio è utilizzando il metodo factory (). Il metodo factory () ci consente di definire un servizio restituendo un oggetto che contiene funzioni di servizio e dati di servizio. La funzione di definizione del servizio è dove inseriamo i nostri servizi iniettabili, come $ http e $ 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; });

Utilizzando factory () nella nostra app

È facile usare la fabbrica nella nostra applicazione in quanto possiamo semplicemente iniettarla dove ne abbiamo bisogno in fase di esecuzione.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Il metodo service (), d'altra parte, ci consente di creare un servizio definendo una funzione di costruzione. Possiamo usare un oggetto prototipico per definire il nostro servizio, anziché un oggetto javascript non elaborato. Simile al metodo factory (), imposteremo anche gli iniettabili nella definizione della funzione.
  2. Il modo più basso livello per creare un servizio è utilizzando il metodo fornire (). Questo è l'unico modo per creare un servizio che possiamo configurare usando la funzione .config (). Diversamente dai metodi precedenti, imposteremo le iniettabili in una definizione di funzione definita this. $ Get ().

-3

Lo zucchero sintattico è la differenza . È necessario solo il fornitore. O in altre parole, solo il fornitore è il vero angolo, tutti gli altri sono derivati ​​(per ridurre il codice). Esiste anche una versione semplice, chiamata Value () che restituisce solo il valore, nessun calcolo o funzione. Anche il valore è derivato dal provider!

Quindi perché tali complicazioni, perché non possiamo semplicemente usare il provider e dimenticare tutto il resto? Dovrebbe aiutarci a scrivere codice facilmente e a comunicare meglio. E la risposta toungue-in-guancia sarebbe, più complessa diventa la migliore vendita di un quadro sarà.


  • Un provider che può restituire value = Value
  • Un provider che può solo creare un'istanza e restituire = Factory (+ Value)
  • Un provider che può creare un'istanza + fare qualcosa = Servizio (+ Factory, + Value)
  • Un provider = deve contenere una proprietà chiamata $ get (+ Factory, + Service, + Value)

L'iniezione angolare ci dà il primo suggerimento per giungere a questa conclusione.

"$ injector viene utilizzato per recuperare istanze di oggetti come definito dal provider " non servizio, non factory ma provider.

E una risposta migliore sarebbe questa: "Un servizio angolare viene creato da una fabbrica di servizi. Queste fabbriche di servizi sono funzioni che, a loro volta, sono create da un fornitore di servizi. I fornitori di servizi sono funzioni di costruzione. Quando vengono istanziati, devono contenere una proprietà chiamato $ get, che detiene la funzione di factory di servizio. "

Quindi fornitore principale e iniettore e tutto andrà a posto :). E diventa interessante in Typescript quando $ get può essere implementato in un provider ereditando da IServiceProvider.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.