into - inject a service angularjs




angular.service vs angular.factory (6)

l'indizio è nel nome

I servizi e le fabbriche sono simili l'uno all'altro. Entrambi produrranno un oggetto singleton che può essere iniettato in altri oggetti, e quindi sono spesso usati in modo intercambiabile.

Sono destinati ad essere utilizzati semanticamente per implementare diversi modelli di progettazione.

I servizi servono per implementare un modello di servizio

Un modello di servizio è quello in cui l'applicazione è suddivisa in unità di funzionalità logicamente coerenti. Un esempio potrebbe essere un accessor API o un set di business logic.

Ciò è particolarmente importante in Angular perché i modelli angolari sono in genere solo oggetti JSON estratti da un server, quindi è necessario un punto in cui inserire la logica aziendale.

Ecco un servizio Github per esempio. Sa come parlare con Github. Conosce url e metodi. Possiamo iniettarlo in un controller e genererà e restituirà una promessa.

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

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

Le fabbriche implementano un modello di fabbrica

Le fabbriche, d'altro canto, hanno lo scopo di implementare un modello di fabbrica. Un modello di fabbrica in uno in cui usiamo una funzione di fabbrica per generare un oggetto. In genere potremmo usarlo per costruire modelli. Ecco una fabbrica che restituisce un costruttore di autori:

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

Faremmo uso di questo in questo modo:

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

Nota che anche le fabbriche restituiscono singleton.

Le fabbriche possono restituire un costruttore

Poiché una factory restituisce semplicemente un oggetto, può restituire qualsiasi tipo di oggetto che ti piace, inclusa una funzione di costruzione, come vediamo sopra.

Le fabbriche restituiscono un oggetto; i servizi sono nuovi

Un'altra differenza tecnica riguarda il modo in cui i servizi e le fabbriche sono composti. Una funzione di servizio verrà aggiornata per generare l'oggetto. Verrà chiamata una funzione factory che restituirà l'oggetto.

  • I servizi sono costruttori nuovi.
  • Le fabbriche vengono semplicemente chiamate e restituiscono un oggetto.

Ciò significa che in un servizio, aggiungiamo "questo" che, nel contesto di un costruttore, indicherà l'oggetto in costruzione.

Per illustrare questo, ecco lo stesso oggetto semplice creato usando un servizio e una fabbrica:

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

Ho visto sia angular.factory() che angular.service() utilizzati per dichiarare servizi; tuttavia, non angular.service() angular.service ovunque nella documentazione ufficiale.

Qual è la differenza tra i due metodi? Quale dovrebbe essere usato per cosa (supponendo che facciano cose diverse)?


app.factory ('fn', fn) vs. app.service ('fn', fn)

Costruzione

Con le fabbriche, Angular invocherà la funzione per ottenere il risultato. È il risultato che viene memorizzato nella cache e iniettato.

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

Con i servizi, Angular invocherà la funzione di costruzione chiamando new . La funzione costruita viene memorizzata nella cache e iniettata.

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

Implementazione

Le fabbriche in genere restituiscono un oggetto letterale perché il valore restituito è ciò che viene iniettato in controller, blocchi di esecuzione, direttive, ecc.

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

Le funzioni di servizio in genere non restituiscono nulla. Invece, eseguono le funzioni di inizializzazione ed esposizione. Le funzioni possono anche fare riferimento a "questo" poiché è stato costruito utilizzando "nuovo".

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

Conclusione

Quando si tratta di utilizzare fabbriche o servizi, sono entrambi molto simili. Vengono iniettati in controller, direttive, blocchi di esecuzione, ecc. E utilizzati nel codice client praticamente nello stesso modo. Sono anche entrambi singleton - il che significa che la stessa istanza è condivisa tra tutti i luoghi in cui viene iniettato il servizio / fabbrica.

Quindi quale preferisci? O uno - sono così simili che le differenze sono banali. Se scegli l'una rispetto all'altra, tieni presente come sono costruite, in modo da poterle implementare correttamente.


Ho passato un po 'di tempo a cercare di capire la differenza.

E penso che la funzione factory usi il modello del modulo e la funzione di servizio usi il modello standard del costruttore di script java.


In poche parole ..

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

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

const fullName = { firstName: 'john' };

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

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


Tutte le risposte qui sembrano essere intorno al servizio e alla fabbrica, ed è valido poiché era quello che veniva chiesto. Ma è anche importante ricordare che ce ne sono molti altri tra cui provider() , value() e constant() .

La chiave per ricordare è che ognuno è un caso speciale dell'altro. Ogni caso speciale lungo la catena consente di fare la stessa cosa con meno codice. Ognuno ha anche qualche limite aggiuntivo.

Per decidere quando utilizzare il quale si vede solo quello che consente di fare ciò che si vuole in meno codice. Ecco un'immagine che illustra quanto siano simili:

Per una completa spiegazione passo passo e una rapida consultazione su quando utilizzare ognuno di essi è possibile visitare il post del blog in cui ho ottenuto questa immagine da:


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 utilizzi il servizio , Angular 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;
  }
});



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 utilizzarli o modificarli 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 a iTunes makeUrl è una funzione che creerà e restituirà il nostro URL di iTunes amichevole.

Ora che sono disponibili le nostre variabili helper / private e la funzione, aggiungiamo alcune proprietà all'oggetto 'service'. Qualsiasi cosa mettiamo sul "servizio" saremo in grado di utilizzare direttamente in 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 Angular, ti consiglio caldamente 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 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, 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 che provengono dai 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'. 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 line below this creates an obj object that will delegate to the person's prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

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

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

  //return this;
}

Ora avendo questa conoscenza di ciò che la "nuova" parola chiave fa davvero in JavaScript, la creazione di un servizio in Angular 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 capito veramente cosa fa 'new', i servizi sono quasi identici alle fabbriche in Angular.





angular-services