run - AngularJS: Service vs provider vs factory




messaging service angularjs (20)

Quali sono le differenze tra un Service , Provider e Factory in AngularJS?


JS Fiddle Demo

Esempio "Ciao mondo" 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>


Fabbrica

Se assegni ad AngularJS una funzione, AngularJS effettuerà il caching e inserirà il valore restituito 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

Dite ad AngularJS una funzione, AngularJS chiamerà nuova per istanziarla. È 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

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

I provider consentono di configurare il provider prima che AngularJS invochi il $getmetodo per ottenere l'iniettabile.

Esempio:

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

Uso (come iniettabile in un controller)

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

Uso (configurazione del provider prima che $getvenga chiamato per creare l'iniettabile)

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

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

I metodi di value , factory , service , constant e provider sono tutti i fornitori. Insegnano all'iniettore come istanziare i 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 Value Recipe è il caso più semplice, in cui istanziate il Servizio da soli e fornite il valore istanziato all'iniettore.
  • La ricetta di fabbrica fornisce all'iniettore una funzione di fabbrica che chiama quando è necessario istanziare il servizio. Quando viene chiamato, la funzione factory crea e restituisce l'istanza del servizio. Le dipendenze del Servizio vengono iniettate come argomenti delle funzioni. Quindi, usando questa ricetta aggiunge le seguenti abilità:
    • Possibilità di utilizzare altri servizi (avere dipendenze)
    • Inizializzazione del servizio
    • Inizializzazione ritardata / pigra
  • La ricetta di servizio è quasi la stessa della ricetta di fabbrica, ma qui l'iniettore invoca un costruttore con il nuovo operatore invece di una funzione di fabbrica.
  • La ricetta del fornitore è solitamente eccessiva . Aggiunge un ulteriore livello di riferimento indiretto, consentendo di configurare la creazione della fabbrica.

    È necessario utilizzare la ricetta Provider solo quando si desidera esporre un'API per la configurazione a livello di applicazione che deve essere eseguita 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 è uguale alla ricetta del valore, tranne che consente di definire i servizi disponibili nella fase di configurazione . Prima dei servizi creati utilizzando la ricetta Valore. A differenza dei valori, non possono essere decorati con decorator .
Vedi la documentazione del provider .


Comprensione di AngularJS Factory, Service e Provider

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

Dal Service/Factory :

  • Istanziata in modo semplice - Angolare crea un'istanza di servizio / fabbrica solo quando un componente dell'applicazione dipende da esso.
  • Singoli - Ogni componente che dipende da un servizio ottiene un riferimento alla singola istanza generata dalla fabbrica del servizio.

Fabbrica

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

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 diversi controller quando lo si sta iniettando all'interno delle funzioni del controller / fabbrica / direttiva. Viene creato solo una volta per app.

Servizio

Semplicemente guardando i servizi pensate al prototipo dell'array. Un servizio è una funzione che crea un'istanza di un nuovo oggetto utilizzando la parola chiave 'nuova'. È possibile aggiungere proprietà e funzioni a un oggetto servizio utilizzando la parola chiave this . A differenza di una factory, 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 hai bisogno di 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 di servizio configurabile. È possibile configurare le impostazioni del servizio dalla funzione di configurazione. Restituisce un valore usando la $get()funzione. La $getfunzione viene eseguita nella 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 basata su modulo per il proprio oggetto di servizio prima di renderlo disponibile, ad es. si supponga di voler impostare l'URL dell'API in base al proprio ambiente come dev, stageoprod

NOTA

Solo il fornitore sarà disponibile nella fase di configurazione angolare, mentre il servizio e la fabbrica non lo sono.

Spero che questo abbia chiarito le tue conoscenze su Factory, Service e Provider .


Servizio vs fornitore vs fabbrica:

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

Prima di tutto, parliamo di servizi in AngularJS!

Cos'è il servizio: in AngularJS, servizionon è altro che un oggetto JavaScript singleton che può memorizzare alcuni metodi o proprietà utili. Questo oggetto singleton viene creato per base (app Angular) e viene 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 di un'istanza di servizio, Angular cerca nel registro il nome di questo servizio e restituisce il riferimento all'oggetto servizio. Tale che possiamo invocare il metodo, accedere alle proprietà ecc. Sull'oggetto servizio. Potresti avere una domanda se puoi anche mettere le proprietà, i metodi sull'oggetto scope dei controller! Allora perché hai bisogno di un oggetto di servizio? Le risposte sono: i servizi sono condivisi tra più ambiti di controllo. Se si inseriscono alcune proprietà / metodi nell'oggetto di un ambito del controllore, esso sarà disponibile solo per l'ambito corrente.Tuttavia, quando si definiscono i metodi, le proprietà sull'oggetto servizio, sarà disponibile a livello globale e si può accedere in qualsiasi ambito del controllore mediante l'iniezione di quel servizio.

Quindi, se ci sono tre scope del controller, sia controllerA, controllerB e controllerC, tutti condivideranno la stessa istanza di 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 fornisce diversi metodi per registrare un servizio. Qui ci concentreremo su tre metodi factory (..), service (..), provider (..);

Usa questo link per il codice di riferimento

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 del servizio invocando la funzione fnFactory () come di seguito.

var serviceInstace = fnFactory();

La funzione passata può definire un oggetto e restituire quell'oggetto. AngularJS memorizza semplicemente questo riferimento oggetto a una variabile che viene passata come primo argomento. Tutto ciò che viene restituito da fnFactory sarà associato a serviceInstance. Invece di restituire un oggetto, possiamo anche restituire la funzione, i valori ecc. Qualsiasi 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(){})

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

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. Cerchiamo di essere interessati a creare un servizio che mostri solo un messaggio di saluto all'utente. 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? Ci deve essere un modo, in modo che l'app possa passare i propri messaggi di saluto personalizzati e Angularjs lo renderebbe disponibile alla funzione factory / constructor che crea la nostra istanza di servizi. In tal caso, la funzione provider () esegue il lavoro. utilizzando la funzione provider () possiamo creare servizi configurabili.

Possiamo creare servizi configurabili usando 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?

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

var serviceProvider = new serviceProviderConstructor();

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

configureService(serviceProvider);

3. L'istanza di servizio finale viene creata chiamando il metodo $ get di serviceProvider.

serviceInstance = serviceProvider.$get()

Il codice di esempio per la creazione del servizio utilizzando fornisce la sintassi:

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:

Fabbrica usa una funzione di fabbrica che restituisce un'istanza di servizio. serviceInstance = fnFactory ();

Il servizio utilizza una funzione di costruzione e Angular richiama questa funzione di costruzione utilizzando la parola chiave 'new' per creare l'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 servizio. La sintassi del provider ha un ulteriore vantaggio di configurare l'oggetto servizio prima che venga istanziato. serviceInstance = $ get ();


TL; DR

1) Quando usi una Fabbrica , crei un oggetto, aggiungi delle proprietà, quindi restituisci lo stesso oggetto. Quando si passa questo stabilimento al controller, tali proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la 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 il servizio , AngularJS lo istanzia dietro le quinte con la parola chiave 'nuova'. Per questo motivo, aggiungi proprietà a "this" e il servizio restituirà "this". Quando si passa il servizio nel controller, tali 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 la configurazione a livello di modulo per il proprio oggetto di 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) fabbrica
Le fabbriche sono il modo più popolare per creare e configurare un servizio. Non c'è davvero molto di più di quello che TL, DR ha detto. Devi solo creare un oggetto, aggiungere proprietà ad esso, quindi restituire lo stesso oggetto. Quindi, quando si passa la fabbrica nel controller, tali proprietà sull'oggetto saranno ora disponibili in quel controller attraverso la fabbrica. Un esempio più ampio è qui sotto.

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

Ora qualsiasi proprietà che attribuiamo al "servizio" sarà a nostra disposizione quando passeremo "myFactory" nel nostro controller.

Ora aggiungiamo alcune variabili 'private' alla nostra funzione di callback. Questi non saranno direttamente accessibili dal controller, ma alla fine creeremo alcuni metodi getter / setter su 'service' per poter 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 quelle variabili / funzioni a 'servizio'. Li stiamo semplicemente creando per poterli utilizzare o modificare in seguito.

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

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

Creeremo metodi setArtist e getArtist che semplicemente restituiscono o impostano l'artista. Stiamo anche creando un metodo che chiamerà l'API di iTunes con il nostro URL creato. Questo metodo restituirà una promessa che si realizzerà non appena i dati torneranno dall'API di iTunes. Se non hai avuto molta esperienza nell'usare promesse in AngularJS, consiglio vivamente di fare un tuffo profondo su di loro.

Sotto setArtist accetta un artista e 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 perché $ 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, oppure la rifiutiamo con un messaggio che dice "C'era 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 allegato 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 ci stiamo iniettando nel servizio 'myFactory'. Quindi impostiamo le proprietà sul nostro oggetto $ scope con i dati di "myFactory". L'unico codice difficile sopra è se non hai mai affrontato le promesse prima. Poiché callItunes sta restituendo una promessa, siamo in grado di utilizzare il metodo .then () e di impostare $ scope.data.artistData una volta che la nostra promessa è stata soddisfatta 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 è quella di creare un'istanza con la parola chiave "nuova". Per voi guru JavaScript questo dovrebbe darvi un grande suggerimento sulla natura del codice. Per quelli di voi con uno sfondo limitato in JavaScript o per coloro che non conoscono troppo bene la parola chiave "nuova", esaminiamo alcuni concetti fondamentali di JavaScript che alla fine ci aiuteranno a capire la natura di un servizio.

Per vedere veramente i cambiamenti che si verificano quando invochi una funzione con la parola chiave 'nuova', creiamo una funzione e la invochiamo con la 'nuova' parola chiave, 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 "nuova" parola chiave, "questo" sarà associato all'oggetto appena creato.

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

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

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

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

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

Quindi, tutto il codice per creare un costruttore Person, aggiungere una funzione al suo prototipo, creare un'istanza Persona 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 vediamo cosa succede realmente 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 di Person sta restituendo un oggetto, se possiamo vederlo nel codice oppure no. 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 Persona sta restituendo deve delegare al suo prototipo su ricerche fallite. In termini più semplici, quando chiamiamo tyler.sayName () l'interprete dice "OK, vado a cercare sull'oggetto 'tyler' che abbiamo appena creato, individuare la funzione sayName, quindi chiamarla. Aspetta un attimo, non lo vedo qui - tutto quello 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 per come puoi pensare a ciò che la parola chiave "nuova" 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 la "nuova" parola chiave fa davvero 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 vengono istanziati con la parola chiave 'nuova'. Combinando questa conoscenza con i nostri esempi sopra, ora dovresti riconoscere che allegerai le tue proprietà e i tuoi metodi direttamente a "questo" che verrà poi restituito dal Servizio stesso. Diamo un'occhiata a questo in azione.

A differenza di ciò che originariamente avevamo fatto con l'esempio Factory, non abbiamo bisogno di creare un oggetto, quindi restituire quell'oggetto perché, come accennato molte volte prima, abbiamo usato la parola chiave 'new' in modo che l'interprete crei quell'oggetto, lo faccia delegare a è un prototipo, quindi restituiscilo per noi senza che noi dobbiamo fare il lavoro.

Per prima cosa, creiamo la nostra funzione "privata" e di aiuto. Questo dovrebbe sembrare molto familiare dato che 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 per "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;
  }

});

Ora, proprio come nella nostra fabbrica, setArtist, getArtist e callItunes saranno disponibili in qualsiasi controller in cui passiamo myService. Ecco il controller myService (che è quasi esattamente lo stesso del 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 detto prima, una volta compreso veramente cosa fa 'new', i servizi sono quasi identici alle fabbriche di AngularJS.

3) Provider

La cosa più importante da ricordare sui provider è che sono l'unico servizio che è possibile trasferire nella parte app.config dell'applicazione. Questo è di grande importanza se hai bisogno di modificare parte del tuo oggetto di servizio prima che sia disponibile ovunque nella tua applicazione. Sebbene siano molto simili a Servizi / Fabbriche, ci sono alcune differenze di cui discuteremo.

Per prima cosa impostiamo il nostro Provider in un modo simile che abbiamo fatto con il nostro servizio e la fabbrica. Le variabili sottostanti 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;
  }
}

* Di nuovo, se qualche parte del codice sopra è confusa, controlla la sezione Factory dove spiego cosa fa tutti i dettagli maggiori.

Puoi pensare ai Provider come aventi tre sezioni. La prima sezione è le variabili / funzioni 'private' che verranno modificate / impostate in un secondo momento (mostrato sopra). La seconda sezione è le variabili / funzioni che saranno disponibili nella tua funzione app.config e sono quindi disponibili per alterare prima che siano disponibili altrove (anche mostrato sopra). È importante notare che queste variabili devono essere associate alla parola chiave "this". Nel nostro esempio, solo "cosaFromConfig" sarà disponibile per modificare in app.config. La terza sezione (mostrata sotto) è tutte le variabili / funzioni che saranno disponibili nel controller quando si passa il servizio 'myProvider' in quel controller specifico.

Quando si crea un servizio con il provider, le sole proprietà / metodi che saranno disponibili nel controller sono quelle proprietà / metodi restituiti dalla funzione $ get (). Il codice qui sotto mette $ get su 'this' (che sappiamo sarà eventualmente restituito da tale funzione). Ora, la funzione $ get restituisce tutti i metodi / proprietà che vogliamo siano 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 Provider completo appare così

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

Ora, proprio come nella nostra fabbrica e nel nostro servizio, setArtist, getArtist e callItunes saranno disponibili in qualsiasi controller in cui passiamo myProvider. Ecco il controller myProvider (che è quasi esattamente lo stesso del nostro controller di fabbrica / servizio).

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 di creazione di un servizio con Provider è di essere in grado di modificare alcune variabili tramite 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 questo appare nel DOM, sarà 'Questa frase è stata impostata ...'.


Di seguito la mia comprensione è molto semplice.

Fabbrica: basta creare un oggetto all'interno della fabbrica e restituirlo.

Servizio:

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

Provider:

C'è un $getoggetto che si definisce e può essere utilizzato per ottenere l'oggetto che restituisce i dati.


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

  • L'iniettore utilizza le 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.
  • La fabbrica e il servizio sono le ricette più utilizzate. L'unica differenza tra loro è che la ricetta del servizio funziona meglio per oggetti di un tipo personalizzato, mentre la 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 fornitore è il tipo di ricetta più complesso. Non ne hai bisogno a meno che non stai costruendo un pezzo di codice riutilizzabile che richiede una configurazione globale.
  • Tutti gli oggetti speciali ad eccezione del controller sono definiti tramite ricette di fabbrica.

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

  1. Se si desidera utilizzare nel modulo angolare, la funzione di configurazione dovrebbe essere creata come fornitore

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

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

Per gli scenari di base, fabbrica e servizio si comportano allo stesso modo.


Ho notato qualcosa di interessante quando giocavo con i provider.

La visibilità degli iniettabili è diversa per i fornitori rispetto a servizi e fabbriche. Se dichiari una "costante" di AngularJS (ad esempio myApp.constant('a', 'Robert');), puoi inserirla in servizi, fabbriche e fornitori.

Ma se si dichiara un "valore" di AngularJS (ad esempio., myApp.value('b', {name: 'Jones'});), È possibile inserirlo nei servizi e nelle fabbriche, ma NON nella funzione di creazione del provider. Tuttavia, è possibile iniettarlo nella $getfunzione che si definisce per il proprio provider. Questo è menzionato nella documentazione di AngularJS, ma è facile non vederlo. Puoi trovarlo nella pagina% di fornitura nelle sezioni relative al valore e ai 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>

Il mio chiarimento al riguardo:

Fondamentalmente tutti i tipi menzionati (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 antiquate.

Mentre le variabili globali non sono raccomandate, l'uso reale di queste variabili globali è quello di fornire un'iniezione di dipendenza , passando la variabile al controller pertinente.

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

  1. Costante
    Questo definisce una costante effettiva che non dovrebbe essere modificata durante l'intera applicazione, proprio come le costanti in altre lingue (qualcosa che manca a JavaScript).
  2. Valore
    Questo è un valore o un oggetto modificabile e funge da variabile globale, che può anche essere iniettata quando si creano altri servizi o fabbriche (vedere oltre su questi). Tuttavia, deve essere un " valore letterale ", il che significa che uno deve scrivere il valore effettivo e non può usare alcuna logica di calcolo o programmazione (in altre parole 39 o myText o {prop: "value"} sono OK, ma 2 +2 non lo è).
  3. Fabbrica
    Un valore più generale, che è possibile calcolare immediatamente. Funziona passando una funzione a AngularJS con la logica necessaria per calcolare il valore e AngularJS la esegue, e salva il valore di ritorno 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 di fabbrica più ridotta 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 al proprietà dell'oggetto utilizzando la parola chiave this .
  5. Provider
    A differenza di un servizio che è una versione semplificata di fabbrica , un provider è un modo più complesso, ma più flessibile di inizializzare le variabili "globali", con la massima flessibilità essendo l'opzione per impostare valori da app.config.
    Funziona come utilizzando una combinazione di servizi e fornitore , passando per provider di una funzione che ha proprietà dichiarate usando la questa parola chiave, che può essere usato dal app.config.
    Quindi è necessario disporre di una funzione $ .get separata che viene eseguita da AngularJS dopo aver impostato le proprietà di cui sopra tramite il app.configfile, e questa funzione $ .get si comporta esattamente come la fabbrica sopra, in quanto il suo valore di ritorno è usato per inizializzare le variabili "globali".

Questa è una parte molto confusa per 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 solo servizio viene creata un'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 di questo è di nuovo lo stesso, tuttavia Provider fornisce l'output della sua funzione $ get.

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


Questa risposta indirizza l'argomento / domanda

come Fabbrica, Servizio e Costante - sono solo zucchero sintattico in cima alla ricetta di un fornitore?

O

come fabbrica, servic e provider sono simailari internamente

in fondo quello che succede è

Quando si effettua un factory()set si functionfornisce in secondo argomento al provider $gete lo si restituisce ( provider(name, {$get:factoryFn })), tutto ciò che si ottiene è providerma non esiste alcuna proprietà / metodo diverso da$get quello provider(significa che non è possibile configurarlo)

Codice sorgente della fabbrica

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

Quando si effettua un service()ritorno si fornisce una factory () con una functionche inietta constructor(restituisce l'istanza della funzione di costruzione fornita nel servizio) e la restituisce

Codice sorgente del servizio

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

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


A seconda della memoria, i controller vengono istanziati solo quando sono necessari e scartati quando non lo sono. Per questo motivo, ogni volta che si cambia rotta o si ricarica una pagina, Angular pulisce il controller corrente. I servizi forniscono tuttavia un mezzo per mantenere i dati in giro per tutta la durata di un'applicazione mentre possono essere utilizzati anche tra diversi controller in modo coerente.

Angular ci fornisce tre modi per creare e registrare il nostro servizio.

1) fabbrica

2) Servizio

3) Provider

Fabbrica : una fabbrica è una semplice funzione che consente di aggiungere una certa logica prima di creare l'oggetto. Restituisce l'oggetto creato.

È solo una raccolta di funzioni come una classe. Quindi, può essere istanziato in diversi controller quando lo si utilizza con la funzione di costruzione.

Servizio : un servizio è una funzione di costruzione che crea l'oggetto utilizzando una nuova parola chiave. È possibile aggiungere proprietà e funzioni a un oggetto servizio utilizzando questa parola chiave. A differenza della fabbrica, non restituisce nulla.

È un oggetto singleton. Usalo quando hai bisogno di condividere un singolo oggetto attraverso l'applicazione. Ad esempio, i dettagli dell'utente autenticato.

Provider : un provider viene utilizzato per creare un oggetto di servizio configurabile. Restituisce valore usando la funzione $ get ().

Quando è necessario fornire una configurazione basata su modulo per il proprio oggetto di servizio prima di renderlo disponibile.

Esegui il seguente codice e vedi l'output.

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


Come sottolineato da più persone qui correttamente, una fabbrica, un fornitore, un servizio e persino un valore e una costante sono versioni della stessa cosa. Puoi sezionare il più generale providerin tutti loro. Così:

Ecco l'articolo di questa immagine tratta da:


Discutiamo i tre modi di gestire la logica di business 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. Istanziato in modo laziale : se non viene iniettato, non verrà mai istanziato. Quindi per usarlo dovrà iniettarlo in un modulo.
  2. Singleton : se iniettato su più moduli, tutti avranno accesso a una sola istanza particolare. Questo è il motivo per cui è 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 precedenti 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 lo schema di progettazione della fabbrica. La fabbrica è un luogo centrale che produce nuovi oggetti o funzioni.
  2. Non solo produce servizi singleton, ma personalizzabili.
  3. Il .service()metodo è una fabbrica che produce sempre lo stesso tipo di servizio, che è un singleton e senza alcun modo semplice per configurare il suo comportamento. Questo .service()metodo viene solitamente utilizzato come scorciatoia per qualcosa che non richiede alcuna configurazione.

PROVIDER

Diamo prima un'occhiata alla sintassi:

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

}

Funzionalità del Provider:

  1. Il fornitore è il metodo più flessibile per creare servizi in Angular.
  2. Non solo possiamo creare una fabbrica che sia configurabile dinamicamente, ma al momento di utilizzare la fabbrica, con il metodo del fornitore, potremmo configurare la fabbrica una volta sola all'avvio della nostra intera applicazione.
  3. La fabbrica può quindi essere utilizzata in tutta l'applicazione con impostazioni personalizzate. In altre parole, possiamo configurare questo factory prima che l'applicazione abbia inizio. Infatti nella documentazione angolare viene menzionato che il metodo provider è ciò che viene effettivamente eseguito dietro le quinte quando configuriamo i nostri servizi con uno .serviceo più .factorymetodi.
  4. La $getè una funzione direttamente collegata all'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à, è una funzione, è ciò che rende il provider un fornitore . AngularJS si aspetta che il provider abbia una proprietà $ get il cui valore è una funzione che Angular considera come una funzione di fabbrica. Ma ciò che rende questa installazione di tutto il provider molto speciale, è il fatto che possiamo fornire qualche configoggetto all'interno del fornitore di servizi e che di solito viene fornito con valori predefiniti che possiamo sovrascrivere in seguito nel passaggio, dove possiamo configurare l'intera applicazione.

Ecco un codice per i broilerplate che ho creato come un 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 si aspettano un oggetto "Posizione" che esponga latitudine e longitudine, ma tramite proprietà di oggetti diverse. Non volevo hackerare il codice del venditore, quindi ho regolato 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

;


Per me, la rivelazione è arrivata quando ho capito che funzionano tutti allo stesso modo: eseguendo qualcosa una volta , memorizzando il valore che ottengono, e poi tossendo su quello stesso valore memorizzato quando si fa riferimento all'iniezione delle dipendenze .

Diciamo 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 dalla corsa fn.
  2. bIl valore memorizzato proviene da newing fn.
  3. cIl valore memorizzato viene dal primo ottenimento di un'istanza mediante newing fne quindi dall'esecuzione di un $getmetodo dell'istanza.

Il che significa che c'è qualcosa come un oggetto cache all'interno di AngularJS, il cui valore di ciascuna 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 utilizziamo i thisservizi e definiamo un this.$getfornitore.


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

Ho trovato questo video che spiega chiaramente le metodologie di fabbrica, di servizio e di fornitore per lo sviluppo di 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 "factory" è il seguente (che include sia le versioni sync che async insieme al servizio http chiamante):

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 (è molto 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 (è 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>


Tutte le buone risposte già. Vorrei aggiungere qualche altro punto su Service and Factory . Insieme alla differenza tra servizio / fabbrica. E uno può anche avere domande come:

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

Iniziamo con la differenza tra Service e factory:

  1. Entrambi sono singleton : ogni volta che Angular li trova come una 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 un comportamento : entrambi possono avere 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 istanzia da chiamare nuovo 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 chiama Angular new yourServiceName(), riceverà l' thisoggetto con tutte le proprietà che gli hai messo.

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 es. 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 con questo è che ScoreKeeper.setScoreverrà chiamato con il thisvincolo nulle otterrai degli errori. Il modo migliore sarebbe $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Indipendentemente dal fatto che tu scelga di usarlo nei tuoi metodi di servizio, 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 (ie, an Object)da una constructorfunzione, il chiamante otterrà tale oggetto anziché questa istanza.

Ciò significa che puoi sostanzialmente copiare e incollare l'esempio di fabbrica dal basso, sostituirlo factorycon service, e 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 invece dell'istanza MyService.

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

fabbriche:

Una fabbrica è 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 è restituire un oggetto con funzioni come proprietà, come questo:

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

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

  return api;
});

Il valore iniettato per una dipendenza di fabbrica è il valore di ritorno della fabbrica e non deve essere un oggetto. Potrebbe essere una funzione

Risposte per sopra 1 e 2 domande:

Per la maggior parte, basta usare le fabbriche per tutto. Il loro comportamento è più facile da capire. Non è possibile decidere se restituire un valore o meno e, inoltre, non introdurre errori se si fa la cosa sbagliata.

Mi riferisco ancora a loro come "servizi" quando sto parlando di iniettarli come dipendenze, però.

Il comportamento di Service / Factory è molto simile, e alcune persone diranno che uno va bene. Questo è un po 'vero, ma trovo più semplice seguire il consiglio della guida di stile di John Papa e limitarmi alle fabbriche. **


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

La factory restituisce una funzione che può essere invocata:

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

La 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 richiamato:

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

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





angularjs-provider