it-swarm.com.de

AngularJS: Service gegen Provider gegen Factory

Was sind die Unterschiede zwischen einem Service, Provider und Factory in AngularJS?

3283
Lior

Aus der AngularJS-Mailingliste habe ich einen erstaunlichen Thread erhalten, der Service vs. Fabrik vs. Anbieter und deren Injection-Nutzung erklärt. Antworten zusammenstellen:

Dienstleistungen

Syntax: module.service( 'serviceName', function );
Ergebnis: Wenn Sie serviceName als injizierbares Argument deklarieren, erhalten Sie eine Instanz der Funktion. Mit anderen Worten new FunctionYouPassedToService().

Fabriken

Syntax: module.factory( 'factoryName', function );
Ergebnis: Wenn Sie factoryName als injizierbares Argument deklarieren, erhalten Sie den Wert , der durch Aufrufen der an module.factory übergebenen Funktionsreferenz zurückgegeben wird.

Anbieter

Syntax: module.provider( 'providerName', function );
Ergebnis: Wenn Sie providerName als injizierbares Argument deklarieren, erhalten Sie (new ProviderFunction()).$get(). Die Konstruktorfunktion wird vor dem Aufruf der $ get-Methode instanziiert - ProviderFunction ist die an module.provider übergebene Funktionsreferenz.

Anbieter haben den Vorteil, dass sie während der Modulkonfigurationsphase konfiguriert werden können.

Siehe hier für den bereitgestellten Code.

Hier ist eine weitere Erklärung von Misko:

provide.value('a', 123);

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

In diesem Fall gibt der Injektor den Wert einfach so zurück, wie er ist. Aber was ist, wenn Sie den Wert berechnen möchten? Dann nutzen Sie eine Fabrik

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

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

factory ist also eine Funktion, die für die Wertschöpfung zuständig ist. Beachten Sie, dass die Factory-Funktion nach anderen Abhängigkeiten fragen kann.

Aber was ist, wenn Sie mehr OO sein und eine Klasse namens Greeter haben möchten?

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

Dann müssten Sie schreiben, um zu instanziieren

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

Dann könnten wir in einem Controller wie diesem nach einem Begrüßer fragen

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

Aber das ist viel zu wortreich. Ein kürzerer Weg, dies zu schreiben, wäre provider.service('greeter', Greeter);

Was aber, wenn wir die Klasse Greeter vor der Injektion konfigurieren wollten? Dann könnten wir schreiben

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

Dann können wir das machen:

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

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

Als Randnotiz werden service, factory und value alle vom Anbieter abgeleitet.

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

JS Fiddle Demo

Beispiel "Hallo Welt" mit 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>
809
EpokK

TL; DR

1) Wenn Sie ein Factory verwenden, erstellen Sie ein Objekt, fügen ihm Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie diese Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar.

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) Wenn Sie Service verwenden, instanziiert AngularJS es mit dem Schlüsselwort "new" hinter den Kulissen. Aus diesem Grund fügen Sie Eigenschaften zu "this" hinzu, und der Service gibt "this" zurück. Wenn Sie den Dienst an Ihren Controller übergeben, sind diese Eigenschaften auf "this" jetzt auf diesem Controller über Ihren Dienst verfügbar.

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

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



)Provider sind der einzige Dienst, den Sie an Ihre .config () - Funktion übergeben können. Verwenden Sie einen Anbieter, wenn Sie eine modulweite Konfiguration für Ihr Dienstobjekt bereitstellen möchten, bevor Sie es verfügbar machen.

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) Fabrik
Fabriken sind die beliebteste Methode zum Erstellen und Konfigurieren eines Dienstes. Es gibt wirklich nicht viel mehr als das, was die TL gesagt hat. Sie erstellen einfach ein Objekt, fügen Eigenschaften hinzu und geben dasselbe Objekt zurück. Wenn Sie dann die Factory an Ihren Controller übergeben, sind diese Eigenschaften für das Objekt jetzt in diesem Controller über Ihre Factory verfügbar. Ein ausführlicheres Beispiel finden Sie weiter unten.

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

Nun stehen uns alle Eigenschaften, die wir mit "Service" verknüpfen, zur Verfügung, wenn wir "myFactory" an unseren Controller übergeben.

Fügen wir unserer Rückruffunktion nun einige "private" Variablen hinzu. Auf diese kann nicht direkt vom Controller aus zugegriffen werden. Wir werden jedoch einige Get-/Setter-Methoden für "service" einrichten, um diese "privaten" Variablen bei Bedarf ändern zu können.

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

Hier werden Sie feststellen, dass wir diese Variablen/Funktionen nicht mit "Service" verknüpfen. Wir erstellen sie lediglich, um sie später entweder zu verwenden oder zu ändern.

  • baseUrl ist die Basis-URL, die die iTunes-API benötigt
  • _artist ist der Künstler, nach dem wir suchen möchten
  • _finalUrl ist die endgültige und vollständig erstellte URL, zu der iTunes aufgerufen wird
  • makeUrl ist eine Funktion, die unsere iTunes-freundliche URL erstellt und zurückgibt.

Nachdem unsere Hilfsvariablen/privaten Variablen und Funktionen vorhanden sind, fügen wir dem Objekt "service" einige Eigenschaften hinzu. Was auch immer wir auf "Service" stellen, kann direkt in dem Controller verwendet werden, an den wir "myFactory" übergeben.

Wir werden setArtist- und getArtist-Methoden erstellen, die den Künstler einfach zurückgeben oder festlegen. Wir werden auch eine Methode erstellen, die die iTunes-API mit unserer erstellten URL aufruft. Diese Methode wird ein Versprechen zurückgeben, das erfüllt wird, sobald die Daten von der iTunes-API zurückgekehrt sind. Wenn Sie noch nicht viel Erfahrung mit Versprechen in AngularJS haben, empfehle ich Ihnen dringend, einen tiefen Tauchgang mit ihnen zu machen.

Unten setArtist akzeptiert einen Künstler und ermöglicht es Ihnen, den Künstler einzustellen. getArtist gibt den Künstler zurück. callItunes ruft zuerst makeUrl () auf, um die URL zu erstellen, die wir für unsere $ http-Anfrage verwenden. Dann wird ein Versprechungsobjekt erstellt, eine $ http-Anfrage mit unserer endgültigen URL gesendet. Da $ http dann eine Versprechung zurückgibt, können wir nach unserer Anfrage .success oder .error aufrufen. Wir lösen dann unser Versprechen mit den iTunes-Daten ein oder lehnen es mit der Meldung "Es ist ein Fehler aufgetreten" ab.

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

Jetzt ist unsere Fabrik fertig. Wir können jetzt "myFactory" in jeden Controller einfügen und dann unsere Methoden aufrufen, die wir an unser Service-Objekt angehängt haben (setArtist, getArtist und 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);
      })
  }
});

Im obigen Controller wird der Dienst "myFactory" eingefügt. Anschließend legen wir Eigenschaften für unser $ scope-Objekt mit Daten aus "myFactory" fest. Der einzige heikle Code oben ist, wenn Sie noch nie mit Versprechungen befasst waren. Da callItunes ein Versprechen zurückgibt, können wir die .then () -Methode verwenden und $ scope.data.artistData erst festlegen, wenn unser Versprechen mit den iTunes-Daten erfüllt ist. Sie werden feststellen, dass unser Controller sehr "dünn" ist (dies ist eine gute Codierungspraxis). Alle unsere logischen und persistenten Daten befinden sich in unserem Service, nicht in unserem Controller.

2) Service
Wenn Sie einen Service erstellen, ist es wahrscheinlich das Wichtigste, dass er mit dem Schlüsselwort "new" instanziiert wird. Für Sie JavaScript-Gurus sollte dies einen großen Hinweis auf die Art des Codes geben. Sehen wir uns für diejenigen unter Ihnen, die nur über begrenzte Kenntnisse in JavaScript verfügen, oder für diejenigen, die nicht genau wissen, was das "neue" Schlüsselwort tatsächlich bewirkt, einige JavaScript-Grundlagen an, die uns letztendlich dabei helfen, die Art eines Dienstes zu verstehen.

Um wirklich zu sehen, welche Änderungen beim Aufrufen einer Funktion mit dem Schlüsselwort "new" auftreten, erstellen Sie eine Funktion und rufen Sie sie mit dem Schlüsselwort "new" auf. Anschließend zeigen wir, was der Interpreter tut, wenn das Schlüsselwort "new" angezeigt wird. Die Endergebnisse sind beide gleich.

Zuerst erstellen wir unseren Konstruktor.

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

Dies ist eine typische JavaScript-Konstruktorfunktion. Wenn wir nun die Funktion "Person" mit dem Schlüsselwort "new" aufrufen, wird "this" an das neu erstellte Objekt gebunden.

Fügen wir nun eine Methode zum Prototyp unserer Person hinzu, damit sie für jede Instanz unserer Personen-Klasse verfügbar ist.

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

Da wir nun die Funktion sayName in den Prototyp einfügen, kann jede Instanz von Person die Funktion sayName aufrufen, um den Namen dieser Instanz zu benachrichtigen.

Nachdem wir nun unsere Person-Konstruktorfunktion und unsere sayName-Funktion in ihrem Prototyp haben, erstellen wir eine Instanz von Person und rufen dann die sayName-Funktion auf.

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

Insgesamt sieht der Code zum Erstellen eines Person-Konstruktors, zum Hinzufügen einer Funktion zum Prototyp, zum Erstellen einer Person-Instanz und zum anschließenden Aufrufen der Funktion für den Prototyp folgendermaßen aus.

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’

Schauen wir uns nun an, was tatsächlich passiert, wenn Sie das Schlüsselwort "new" in JavaScript verwenden. Als Erstes sollten Sie bemerken, dass wir nach der Verwendung von "new" in unserem Beispiel eine Methode (sayName) für "tyler" aufrufen können, als wäre es ein Objekt - das liegt daran, dass es so ist. Zuerst wissen wir also, dass unser Person-Konstruktor ein Objekt zurückgibt, ob wir das im Code sehen oder nicht. Zweitens wissen wir, dass das von der Person-Funktion zurückgegebene Objekt bei fehlgeschlagenen Suchen an den Prototyp delegiert werden muss, da sich unsere sayName-Funktion auf dem Prototyp und nicht direkt auf der Person-Instanz befindet. Einfacher ausgedrückt: Wenn wir tyler.sayName () aufrufen, sagt der Interpreter: "OK, ich werde das soeben erstellte" tyler "-Objekt untersuchen, die Funktion sayName suchen und es dann aufrufen. Moment mal, ich sehe es hier nicht - alles was ich sehe ist Name und Alter, lass mich den Prototyp überprüfen. Ja, es sieht so aus, als wäre es auf dem Prototyp, lass es mich nennen. ".

Im Folgenden finden Sie Code, mit dem Sie überlegen können, was das "neue" Keyword in JavaScript tatsächlich bewirkt. Dies ist im Grunde ein Codebeispiel für den obigen Absatz. Ich habe die "Dolmetscheransicht" oder die Art und Weise festgelegt, wie der Dolmetscher den Code in Notizen sieht.

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

Wenn Sie nun wissen, was das "neue" Schlüsselwort in JavaScript wirklich bewirkt, sollte es einfacher sein, einen Service in AngularJS zu erstellen.

Wenn Sie einen Service erstellen, müssen Sie wissen, dass Services mit dem Schlüsselwort "new" instanziiert sind. Wenn Sie dieses Wissen mit unseren obigen Beispielen kombinieren, sollten Sie jetzt erkennen, dass Sie Ihre Eigenschaften und Methoden direkt mit "this" verknüpfen, das dann vom Service selbst zurückgegeben wird. Sehen wir uns dies in Aktion an.

Im Gegensatz zu dem, was wir ursprünglich mit dem Factory-Beispiel gemacht haben, müssen wir kein Objekt erstellen und dann dieses Objekt zurückgeben, da wir, wie schon oft erwähnt, das Schlüsselwort 'new' verwendet haben, damit der Interpreter dieses Objekt erstellt und delegieren lässt Es ist ein Prototyp, dann senden Sie es für uns zurück, ohne dass wir die Arbeit erledigen müssen.

Lassen Sie uns als Erstes unsere "private" und Hilfsfunktion erstellen. Dies sollte sehr vertraut aussehen, da wir genau dasselbe mit unserer Fabrik gemacht haben. Ich werde hier nicht erklären, was die einzelnen Zeilen tun, da ich dies im Factory-Beispiel getan habe. Wenn Sie verwirrt sind, lesen Sie das Factory-Beispiel erneut.

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

Jetzt werden wir alle unsere Methoden, die in unserem Controller verfügbar sind, an "dies" anhängen.

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

});

Jetzt sind setArtist, getArtist und callItunes genau wie in unserer Fabrik auf jedem Controller verfügbar, an den wir myService übergeben. Hier ist der myService-Controller (der fast genau unserem werkseitigen Controller entspricht).

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

Wie ich bereits erwähnt habe, sind Services, sobald Sie wirklich verstanden haben, was „neu“ bedeutet, fast identisch mit Fabriken in AngularJS.

) Anbieter

Das Wichtigste an Providern ist, dass sie der einzige Dienst sind, den Sie an den app.config-Teil Ihrer Anwendung übergeben können. Dies ist von großer Bedeutung, wenn Sie einen Teil Ihres Serviceobjekts ändern müssen, bevor es an anderer Stelle in Ihrer Anwendung verfügbar ist. Obwohl sehr ähnlich zu Services/Factories, gibt es ein paar Unterschiede, die wir diskutieren werden.

Zuerst haben wir unseren Provider auf ähnliche Weise wie unseren Service und unsere Fabrik eingerichtet. Die folgenden Variablen sind unsere "private" und Hilfsfunktion.

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

* Wiederum, wenn irgendein Teil des obigen Codes verwirrend ist, lesen Sie den Factory-Abschnitt, in dem ich Ihnen erkläre, was alles für weitere Details erforderlich ist.

Sie können sich Anbieter mit drei Abschnitten vorstellen. Der erste Abschnitt enthält die "privaten" Variablen/Funktionen, die später geändert/festgelegt werden (siehe oben). Der zweite Abschnitt enthält die Variablen/Funktionen, die in Ihrer app.config-Funktion verfügbar sind und daher geändert werden können, bevor sie an einer anderen Stelle verfügbar sind (siehe auch oben). Beachten Sie, dass diese Variablen mit dem Schlüsselwort "this" verknüpft werden müssen. In unserem Beispiel kann nur "thingFromConfig" in der app.config geändert werden. Der dritte Abschnitt (siehe unten) enthält alle Variablen/Funktionen, die in Ihrem Controller verfügbar sind, wenn Sie den Dienst "myProvider" an diesen bestimmten Controller übergeben.

Wenn Sie einen Dienst mit Provider erstellen, sind die einzigen Eigenschaften/Methoden, die in Ihrem Controller verfügbar sind, die Eigenschaften/Methoden, die von der Funktion $ get () zurückgegeben werden. Der folgende Code setzt $ get auf "this" (von dem wir wissen, dass es irgendwann von dieser Funktion zurückgegeben wird). Diese $ get-Funktion gibt nun alle Methoden/Eigenschaften zurück, die im Controller verfügbar sein sollen. Hier ist ein Codebeispiel.

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

Nun sieht der vollständige Provider-Code so aus

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

Jetzt sind setArtist, getArtist und callItunes genau wie in unserer Factory und unserem Service auf jedem Controller verfügbar, an den wir myProvider übergeben. Hier ist der myProvider-Controller (der fast genau unserem Werks-/Service-Controller entspricht).

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

Wie bereits erwähnt, besteht der springende Punkt beim Erstellen eines Dienstes mit Provider darin, einige Variablen über die Funktion app.config ändern zu können, bevor das endgültige Objekt an den Rest der Anwendung übergeben wird. Sehen wir uns ein Beispiel dafür an.

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

Jetzt können Sie sehen, wie "thingFromConfig" als leere Zeichenfolge in unserem Provider ist. Wenn dies jedoch im DOM angezeigt wird, lautet die Zeichenfolge "Dieser Satz wurde gesetzt ...".

644
Tyler McGinnis

Grundlegendes zu AngularJS Factory, Service und Provider

All dies wird verwendet, um wiederverwendbare Singleton-Objekte gemeinsam zu nutzen. Es ist hilfreich, wiederverwendbaren Code in Ihrer App/in verschiedenen Komponenten/Modulen gemeinsam zu nutzen.

Von Docs Service/Werk :

  • Lazily instantiated - Angular instanziiert einen Service/eine Factory nur, wenn eine Anwendungskomponente davon abhängt.
  • Singletons - Jede von einem Service abhängige Komponente erhält einen Verweis auf die von der Service Factory generierte Einzelinstanz.

Fabrik

Eine Factory ist eine Funktion, mit der Sie Logik manipulieren/hinzufügen können, bevor Sie ein Objekt erstellen. Anschließend wird das neu erstellte Objekt zurückgegeben.

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

Verwendung

Es kann nur eine Sammlung von Funktionen wie eine Klasse sein. Daher kann es in verschiedenen Controllern instanziiert werden, wenn Sie es in Ihre Controller-/Factory-/Direktiven-Funktionen einfügen. Es wird nur einmal pro App instanziiert.

Bedienung

Denken Sie beim Betrachten der Services einfach an den Array-Prototyp. Ein Service ist eine Funktion, die ein neues Objekt mit dem Schlüsselwort 'new' instanziiert. Sie können einem Serviceobjekt Eigenschaften und Funktionen hinzufügen, indem Sie das Schlüsselwort this verwenden. Im Gegensatz zu einer Factory gibt sie nichts zurück (sie gibt ein Objekt zurück, das Methoden/Eigenschaften enthält).

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

Verwendung

Verwenden Sie diese Option, wenn Sie ein einzelnes Objekt in der gesamten Anwendung freigeben müssen. Zum Beispiel authentifizierte Benutzerdetails, gemeinsam nutzbare Methoden/Daten, Dienstprogrammfunktionen usw.

Anbieter

Ein Provider wird verwendet, um ein konfigurierbares Dienstobjekt zu erstellen. Sie können die Diensteinstellungen über die Konfigurationsfunktion konfigurieren. Mit der Funktion $get() wird ein Wert zurückgegeben. Die Funktion $get wird in der Laufphase im Winkel ausgeführt.

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

Verwendung

Wenn Sie eine modulweise Konfiguration für Ihr Serviceobjekt vornehmen müssen, bevor Sie es verfügbar machen, z. Angenommen, Sie möchten Ihre API-URL auf der Grundlage Ihrer Umgebung wie dev, stage oder prod festlegen.

NOTE

In der Konfigurationsphase von Angular ist nur der Anbieter verfügbar, während dies bei Service und Werk nicht der Fall ist.

Hoffe, dies hat Ihr Verständnis für Factory, Service und Provider geklärt.

223
Pankaj Parkar

Für mich kam die Enthüllung, als ich feststellte, dass sie alle auf die gleiche Weise funktionieren: indem ich etwas einmal laufen ließ, den Wert speicherte, den sie erhielten, und dann husten derselbe gespeicherte Wert , wenn durch Abhängigkeitsinjektion verwiesen wird.

Sagen wir, wir haben:

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

Der Unterschied zwischen den drei ist, dass:

  1. Der gespeicherte Wert von a stammt aus der Ausführung von fn.
  2. Der gespeicherte Wert von b stammt von newing fn.
  3. Der gespeicherte Wert von c stammt aus dem Abrufen einer Instanz durch newing fn und anschließender Ausführung einer $get -Methode der Instanz.

Was bedeutet, dass sich in AngularJS so etwas wie ein Cache-Objekt befindet, dessen Wert jeder Injektion nur einmal zugewiesen wird, wenn sie das erste Mal injiziert wurden und wo:

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

Aus diesem Grund verwenden wir this in Diensten und definieren this.$get in Anbietern.

192
Lucia

Service vs. Anbieter vs. Fabrik:

Ich versuche es einfach zu halten. Es dreht sich alles um das grundlegende JavaScript-Konzept.

Lassen Sie uns zunächst über Services in AngularJS sprechen!

Was ist Service: In AngularJS ist Service nichts anderes als ein Singleton-JavaScript Objekt, das einige nützliche Methoden oder Eigenschaften speichern kann. Dieses Singleton-Objekt wird auf Basis von ngApp (Angular App) erstellt und von allen Controllern in der aktuellen App gemeinsam genutzt. Wenn Angularjs ein Dienstobjekt instanziieren, registriert es dieses Dienstobjekt mit einem eindeutigen Dienstnamen. Wenn also eine Dienstinstanz benötigt wird, durchsucht Angular die Registrierung nach diesem Dienstnamen und gibt den Verweis auf das Dienstobjekt zurück. Auf diese Weise können wir die Methode aufrufen, auf Eigenschaften usw. des Serviceobjekts zugreifen. Sie haben vielleicht die Frage, ob Sie auch Eigenschaften, Methoden zum Scope-Objekt von Controllern setzen können! Warum brauchen Sie ein Serviceobjekt? Die Antwort lautet: Dienste werden von mehreren Controllern gemeinsam genutzt. Wenn Sie einige Eigenschaften/Methoden in das Bereichsobjekt eines Controllers einfügen, steht es nur dem aktuellen Bereich zur Verfügung. Wenn Sie jedoch Methoden und Eigenschaften für ein Dienstobjekt definieren, ist es global verfügbar und kann im Bereich eines beliebigen Controllers durch Injizieren dieses Diensts aufgerufen werden.

Wenn es also drei Controller-Bereiche gibt, seien es ControllerA, ControllerB und ControllerC, die alle dieselbe Dienstinstanz verwenden.

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

Wie erstelle ich einen Dienst?

AngularJS bietet verschiedene Methoden zum Registrieren eines Dienstes. Hier konzentrieren wir uns auf drei Methoden Fabrik (..), Service (..), Anbieter (..);

Verwenden Sie diesen Link als Code-Referenz

Werksfunktion:

Wir können eine Fabrikfunktion wie folgt definieren.

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

AngularJS bietet 'factory (' serviceName ', fnFactory)' eine Methode, die zwei Parameter, serviceName und eine JavaScript-Funktion, akzeptiert. Angular erstellt eine Dienstinstanz durch Aufrufen der Funktion fnFactory () wie unten.

var serviceInstace = fnFactory();

Die übergebene Funktion kann ein Objekt definieren und dieses Objekt zurückgeben. AngularJS speichert diese Objektreferenz einfach in einer Variablen, die als erstes Argument übergeben wird. Alles, was von fnFactory zurückgesandt wird, ist an serviceInstance gebunden. Anstatt Objekt zurückzugeben, können wir auch Funktion, Werte usw. zurückgeben. Was auch immer wir zurückgeben, wird der Service-Instanz zur Verfügung stehen.

Beispiel:

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

Service-Funktion:

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

Auf andere Weise können wir einen Dienst registrieren. Der einzige Unterschied besteht darin, wie AngularJS versucht, das Serviceobjekt zu instanziieren. Dieses Mal verwendet angular das Schlüsselwort 'new' und ruft die Konstruktorfunktion wie folgt auf.

var serviceInstance = new fnServiceConstructor();

In der Konstruktorfunktion können wir das Schlüsselwort 'this' verwenden, um dem Serviceobjekt Eigenschaften/Methoden hinzuzufügen. Beispiel:

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

Providerfunktion:

Provider () - Funktion ist die andere Möglichkeit zum Erstellen von Diensten. Wir möchten einen Dienst erstellen, der dem Benutzer nur eine Begrüßungsnachricht anzeigt. Wir möchten jedoch auch eine Funktion bereitstellen, mit der der Benutzer seine eigene Begrüßungsnachricht festlegen kann. In technischer Hinsicht wollen wir konfigurierbare Dienste erstellen. Wie können wir das machen? Es muss eine Möglichkeit geben, dass die App ihre benutzerdefinierten Begrüßungsnachrichten weitergibt und Angularjs diese für die Factory-/Konstruktorfunktion zur Verfügung stellt, die unsere Serviceinstanz erstellt. In einem solchen Fall erledigt die provider () - Funktion den Job. Mit der provider () -Funktion können wir konfigurierbare Dienste erstellen.

Wir können konfigurierbare Dienste mit der unten angegebenen Anbietersyntax erstellen.

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

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

Wie funktioniert die Provider-Syntax intern?

1.Provider-Objekt wird mit der Konstruktorfunktion erstellt, die wir in unserer Provider-Funktion definiert haben.

var serviceProvider = new serviceProviderConstructor();

2.Die in app.config () übergebene Funktion wird ausgeführt. Dies wird als Konfigurationsphase bezeichnet. Hier haben wir die Möglichkeit, unseren Service anzupassen.

configureService(serviceProvider);

3.Die endgültige Dienstinstanz wird durch Aufrufen der Methode $ get von serviceProvider erstellt.

serviceInstance = serviceProvider.$get()

Beispielcode zum Erstellen eines Dienstes mit der Bereitstellungssyntax:

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

Arbeitsdemo

Zusammenfassung:


Factory verwendet eine Factory-Funktion, die eine Service-Instanz zurückgibt. serviceInstance = fnFactory ();

Service verwendet eine Konstruktorfunktion und Angular ruft diese Konstruktorfunktion mit dem Schlüsselwort 'new' zum Erstellen der Service-Instanz auf. serviceInstance = new fnServiceConstructor ();

Provider definiert eine providerConstructor-Funktion, diese providerConstructor-Funktion definiert eine Factory-Funktion $ get . Angular ruft $ get () auf, um das Dienstobjekt zu erstellen. Die Anbietersyntax hat den zusätzlichen Vorteil, dass das Dienstobjekt konfiguriert wird, bevor es instanziiert wird. serviceInstance = $ get ();

136
Anant

Wie von mehreren Personen hier richtig hervorgehoben, sind eine Fabrik, ein Anbieter, ein Dienst und sogar ein Wert und eine Konstante Versionen derselben Sache. Sie können das allgemeinere provider in alle zerlegen. Wie so:

enter image description here

Hier ist der Artikel, aus dem dieses Bild stammt:

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

85
Luis Perez

Fabrik

Wenn Sie AngularJS eine Funktion zuweisen, wird AngularJS den Rückgabewert zwischenspeichern und einspeisen, wenn das Werk angefordert wird.

Beispiel:

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

Verwendungszweck:

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

Bedienung

Sie geben AngularJS eine Funktion, AngularJS ruft new auf, um sie zu instanziieren. Es ist die von AngularJS erstellte Instanz, die zwischengespeichert und injiziert wird, wenn der Service angefordert wird. Da new verwendet wurde, um den Dienst zu instanziieren, wird das Schlüsselwort this ist gültig und bezieht sich auf die Instanz.

Beispiel:

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

Verwendungszweck:

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

Anbieter

Sie geben AngularJS eine Funktion und AngularJS ruft die Funktion $get auf. Dies ist der Rückgabewert der Funktion $get, der zwischengespeichert und eingefügt wird, wenn der Dienst angefordert wird.

Mit Providern können Sie den Provider konfigurieren , bevor AngularJS die Methode $get aufruft, um das Injectible abzurufen.

Beispiel:

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

Verwendung (als Injectable in einem Controller)

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

Verwendung (Konfigurieren des Providers, bevor $get aufgerufen wird, um das injizierbare Objekt zu erstellen)

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

Beim Herumspielen mit Anbietern ist mir etwas Interessantes aufgefallen.

Die Sichtbarkeit von Injectables unterscheidet sich für Anbieter von Services und Fabriken. Wenn Sie eine AngularJS-Konstante deklarieren (z. B. myApp.constant('a', 'Robert');), können Sie sie in Services, Fabriken und Anbieter einspeisen.

Wenn Sie jedoch einen AngularJS-Wert deklarieren (z. B. myApp.value('b', {name: 'Jones'});), können Sie ihn in Dienste und Fabriken einspeisen, jedoch NICHT in die anbietererstellende Funktion. Sie können es jedoch in die $get -Funktion einfügen, die Sie für Ihren Provider definieren. Dies wird in der AngularJS-Dokumentation erwähnt, ist aber leicht zu übersehen. Sie finden es auf der Seite% supply in den Abschnitten zu den Methoden value und constant.

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

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

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

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

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

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

Dies ist für Neulinge sehr verwirrend und ich habe versucht, es in einfachen Worten zu erklären

AngularJS-Dienst: wird zum Teilen von Dienstprogrammfunktionen mit der Dienstreferenz in der Steuerung verwendet. Der Dienst ist singleton-artig, sodass für einen Dienst nur eine Instanz im Browser erstellt wird und auf der gesamten Seite derselbe Verweis verwendet wird.

Im Service erstellen wir Funktionsnamen als Eigenschaft mit diesem Objekt.

AngularJS Factory: Der Zweck von Factory ist ebenfalls derselbe wie der von Service. In diesem Fall erstellen wir jedoch ein neues Objekt und fügen Funktionen als Eigenschaften dieses Objekts hinzu Am Ende geben wir dieses Objekt zurück.

AngularJS-Provider: Der Zweck dieses Providers ist wieder derselbe, jedoch gibt der Provider die Ausgabe seiner $ get-Funktion aus.

Die Definition und Verwendung von Service, Factory und Provider wird unter http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider erläutert

45
Sheo Narayan

Für mich ist die beste und einfachste Art, den Unterschied zu verstehen:

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

So instanziiert AngularJS bestimmte Komponenten (vereinfacht):

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

// factory
var angularFactory = factory(injection);

Für den Dienst wird die AngularJS-Komponente also die Objektinstanz der Klasse, die durch die Dienstdeklarationsfunktion dargestellt wird. Für die Fabrik ist es das Ergebnis, das von der Fabrikdeklarationsfunktion zurückgegeben wird. Die Fabrik verhält sich möglicherweise genauso wie der Service:

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

Die einfachste Denkweise ist die folgende:

  • Service ist eine Singleton-Objektinstanz. Verwenden Sie Dienste, wenn Sie ein Singleton-Objekt für Ihren Code bereitstellen möchten.
  • Factory ist eine Klasse. Verwenden Sie Factorys, wenn Sie benutzerdefinierte Klassen für Ihren Code bereitstellen möchten (kann nicht mit Services ausgeführt werden, da diese bereits instanziiert sind).

Das Beispiel für die Factory-Klasse finden Sie in den Kommentaren sowie in den Anbieterdifferenzen.

34

Meine Klarstellung in dieser Angelegenheit:

Grundsätzlich erstellen und konfigurieren alle genannten Typen (Service, Factory, Provider usw.) nur globale Variablen (die natürlich für die gesamte Anwendung global sind), so wie es altmodische globale Variablen waren.

Während globale Variablen nicht empfohlen werden, besteht die tatsächliche Verwendung dieser globalen Variablen darin, Abhängigkeitsinjektion bereitzustellen, indem die Variable an den entsprechenden Controller übergeben wird.

Es gibt viele Komplikationen bei der Erstellung der Werte für die "globalen Variablen":

  1. Konstante
    Dies definiert eine tatsächliche Konstante, die nicht während der gesamten Anwendung geändert werden sollte, genau wie Konstanten in anderen Sprachen (etwas, das JavaScript fehlt).
  2. Wert
    Dies ist ein veränderbarer Wert oder ein veränderbares Objekt und dient als eine globale Variable, die sogar beim Erstellen anderer Dienste oder Fabriken eingefügt werden kann (siehe weiter unten). Es muss jedoch ein "Literalwert" sein, was bedeutet, dass man den tatsächlichen Wert ausschreiben muss und keine Berechnungs- oder Programmierlogik verwenden kann (mit anderen Worten 9 oder myText ​​oder {prop: "value"} sind OK, aber 2 +2 ist nicht).
  3. Fabrik
    Ein allgemeinerer Wert, der sofort berechnet werden kann. Dazu übergibt AngularJS eine Funktion mit der zur Berechnung des Werts erforderlichen Logik, und AngularJS führt sie aus. Der Rückgabewert wird in der angegebenen Variablen gespeichert.
    Beachten Sie, dass es möglich ist, ein Objekt (in diesem Fall funktioniert es ähnlich wie service) oder eine Funktion (die in der Variablen als Rückruffunktion gespeichert wird) zurückzugeben.
  4. Service
    Ein Dienst ist eine einfachere Version von factory, die nur gültig ist, wenn der Wert ein Objekt ist, und das Schreiben von Logik direkt in die Funktion ermöglicht (als ob dies der Fall wäre) Konstruktor sein) sowie Deklarieren und Zugreifen auf die Objekteigenschaften mit dem Schlüsselwort this.
  5. Anbieter
    Im Gegensatz zu einem Dienst, der eine vereinfachte Version von factory ist, ist ein Anbieter eine komplexere, aber flexiblere Methode zum Initialisieren der "globalen" Variablen, wobei die größte Flexibilität in der Option besteht Werte aus der app.config setzen.
    Es funktioniert wie die Verwendung einer Kombination aus service und provider, indem eine Funktion an provider übergeben wird, deren Eigenschaften mit this deklariert wurden Schlüsselwort, das aus dem app.config verwendet werden kann.
    Dann muss es eine separate $. Get ​​- Funktion geben, die von AngularJS ausgeführt wird, nachdem die obigen Eigenschaften über die app.config -Datei festgelegt wurden, und diese $. Die Funktion get ​​verhält sich genau wie die Funktion factory, dh ihr Rückgabewert wird zum Initialisieren der "globalen" Variablen verwendet.
33
yoel halb

Mein Verständnis ist unten sehr einfach.

Factory: Sie erstellen einfach ein Objekt innerhalb der Factory und senden es zurück.

Service:

Sie haben nur eine Standardfunktion, die dieses Schlüsselwort verwendet, um eine Funktion zu definieren.

Provider:

Es gibt ein $get -Objekt, das Sie definieren, und es kann verwendet werden, um das Objekt abzurufen, das Daten zurückgibt.

26
sajan

Zusammenfassung von Angular docs :

  • Es gibt fünf Rezepttypen, die definieren, wie Objekte erstellt werden: Wert, - Fabrik, Service, Provider und Konstante.
  • Fabrik und Service sind die am häufigsten verwendeten Rezepte. Der einzige Unterschied zwischen ihnen ist, dass das Service Rezept für Objekte eines benutzerdefinierten Typs besser funktioniert, während die Factory kann JavaScript-Primitive und -Funktionen erzeugen.
  • Das -Anbieterrezept ist der Kernrezepttyp, und alle anderen sind nur syntaktischer Zucker darauf.
  • Der Anbieter ist der komplexeste Rezepttyp. Sie benötigen es nur, wenn Sie einen wiederverwendbaren Code erstellen, der eine globale Konfiguration erfordert.

enter image description here


Beste Antworten von SO:

https://stackoverflow.com/a/26924234/16567 (<- GUT) https://stackoverflow.com/a/27263882/16567
https://stackoverflow.com/a/16566144/16567

24
Yarin

Alle guten Antworten schon. Ich möchte noch ein paar Punkte hinzufügen zu Service und Factory. Zusammen mit dem Unterschied zwischen Service/Fabrik. Und man kann auch Fragen haben wie:

  1. Soll ich den Service oder das Werk nutzen? Was ist der Unterschied?
  2. Tun sie dasselbe oder haben sie dasselbe Verhalten?

Beginnen wir mit dem Unterschied zwischen Service und Fabrik:

  1. Beide sind Singletons: Immer wenn Angular diese als Abhängigkeit zum ersten Mal findet, wird eine einzelne Instanz von service/factory erstellt. Sobald die Instanz erstellt wurde, wird dieselbe Instanz für immer verwendet.

  2. Kann verwendet werden, um ein Objekt mit Verhalten zu modellieren: Beide können Methoden, interne Statusvariablen usw. haben. Die Art und Weise, wie Sie diesen Code schreiben, wird sich jedoch unterscheiden.

Dienstleistungen:

Ein Service ist eine Konstruktorfunktion, und Angular instanziiert ihn, indem es new yourServiceName() aufruft. Das bedeutet ein paar Dinge.

  1. Funktionen und Instanzvariablen sind Eigenschaften von this.
  2. Sie müssen keinen Wert zurückgeben. Wenn Angular new yourServiceName() aufruft, erhält es das this -Objekt mit allen Eigenschaften, die Sie ihm zugewiesen haben.

Beispielbeispiel:

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

Wenn Angular diesen MyService Dienst in eine davon abhängige Steuerung einspeist, erhält diese eine MyService, auf die sie Funktionen aufrufen kann, z. MyService.aServiceMethod ().

Sei vorsichtig mit this:

Da der erstellte Service ein Objekt ist, können sich die darin enthaltenen Methoden auf Folgendes beziehen, wenn sie aufgerufen werden:

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

Sie könnten versucht sein, ScoreKeeper.setScore in einer Versprechenskette aufzurufen, wenn Sie beispielsweise die Partitur durch Abrufen vom Server initialisiert haben: $http.get('/score').then(ScoreKeeper.setScore). Das Problem dabei ist, dass ScoreKeeper.setScore mit aufgerufen wird this ist an null gebunden, und es werden Fehler angezeigt. Der bessere Weg wäre $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Ob Sie diese Option für Ihre Dienstmethoden verwenden oder nicht, achten Sie darauf, wie Sie sie aufrufen.

Rückgabe eines Wertes aus einem Service:

Aufgrund der Funktionsweise von JavaScript-Konstruktoren erhält der Aufrufer dieses Objekt anstelle dieser Instanz, wenn Sie einen komplexen Wert (i.e., an Object) von einer constructor -Funktion zurückgeben.

Dies bedeutet, dass Sie das Factory-Beispiel im Prinzip von unten kopieren und einfügen können, factory durch service ersetzen können und es funktioniert:

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

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

Wenn Angular Ihren Dienst mit new MyService () erstellt, wird dieses API-Objekt anstelle der MyService-Instanz abgerufen.

Dies ist das Verhalten für alle komplexen Werte (Objekte, Funktionen), jedoch nicht für primitive Typen.

Fabriken:

Eine Factory ist eine einfache alte Funktion, die einen Wert zurückgibt. Der Rückgabewert ist das, was in fabrikabhängige Dinge injiziert wird. Ein typisches Factory-Muster in Angular besteht darin, ein Objekt mit folgenden Funktionen als Eigenschaften zurückzugeben:

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

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

  return api;
});

Der injizierte Wert für eine Factory-Abhängigkeit ist der Rückgabewert der Factory und muss kein Objekt sein. Es könnte eine Funktion sein

Antworten auf die Fragen 1 und 2:

Meistens bleiben Sie einfach bei der Nutzung von Fabriken für alles. Ihr Verhalten ist leichter zu verstehen. Sie können nicht entscheiden, ob Sie einen Wert zurückgeben möchten oder nicht. Außerdem müssen Sie keine Fehler melden, wenn Sie das Falsche tun.

Ich bezeichne sie immer noch als "Dienste", wenn ich davon spreche, sie als Abhängigkeiten zu injizieren.

Service/Factory-Verhalten ist sehr ähnlich, und einige Leute werden sagen, dass beides in Ordnung ist. Das ist ein bisschen wahr, aber ich finde es einfacher, den Ratschlägen von John Papa zu folgen und einfach bei den Fabriken zu bleiben. **

18
Ved

Es gibt bereits gute Antworten, aber ich möchte diese nur teilen.

Zuallererst: Der Provider ist der Weg/das Rezept, um ein service (Singleton-Objekt) zu erstellen, das mit $ injector (how) injiziert werden soll AngulaJS geht um IoC-Muster).

Und Wert, Fabrik, Service und Konstante (4 Möglichkeiten) - der syntaktische Zucker über Anbieter weg/empfang.

Es ist Service vs Factory Teil behandelt worden: https://www.youtube.com/watch?v=BLzNCkPn3ao

Service dreht sich alles um das new Keyword, das, wie wir wissen, 4 Dinge tut:

  1. erstellt ein brandneues Objekt
  2. verknüpft es mit seinem Objekt prototype
  3. verbindet context mit this
  4. und gibt this zurück

Und Factory handelt von Factory Pattern - enthält Funktionen, die Objekte wie diesen Service zurückgeben.

  1. fähigkeit, andere Dienste zu nutzen (Abhängigkeiten haben)
  2. dienstinitialisierung
  3. verzögerte/verzögerte Initialisierung

Und dieses einfache/kurze Video: behandelt auch Provider : https://www.youtube.com/watch?v=HvTZbQ_hUZY = (dort können Sie sehen, wie sie von der Fabrik zum Anbieter gehen)

Das Provider Rezept wird hauptsächlich in der App-Konfiguration verwendet, bevor die App vollständig gestartet/initialisiert wurde.

16
ses

Eine zusätzliche Klarstellung ist, dass Fabriken Funktionen/Grundelemente erstellen können, während Dienste dies nicht können. Check out this jsFiddle basierend auf Epokks: http://jsfiddle.net/skeller88/PxdSP/1351/ .

Die Factory gibt eine Funktion zurück, die aufgerufen werden kann:

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

Die Factory kann auch ein Objekt mit einer Methode zurückgeben, die aufgerufen werden kann:

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

Der Service gibt ein Objekt mit einer Methode zurück, die aufgerufen werden kann:

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

Weitere Einzelheiten finden Sie in einem Beitrag, den ich zum Unterschied geschrieben habe: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/

16
skeller88

Nachdem ich all diese Beiträge gelesen hatte, wurde es für mich verwirrender. Aber dennoch sind alle Informationen wert. Schließlich fand ich die folgende Tabelle, die Informationen mit einem einfachen Vergleich liefert

  • Der Injektor verwendet Rezepte, um zwei Arten von Objekten zu erstellen: Dienste und Spezialobjekte
  • Es gibt fünf Rezepttypen, die definieren, wie Objekte erstellt werden: Value, Factory, Service, Provider und Constant.
  • Fabrik und Service sind die am häufigsten verwendeten Rezepte. Der einzige Unterschied besteht darin, dass das Dienstrezept für Objekte eines benutzerdefinierten Typs besser funktioniert, während die Factory JavaScript-Grundelemente und -Funktionen erstellen kann.
  • Das Provider-Rezept ist der Kernrezept-Typ und alle anderen sind nur syntaktischer Zucker.
  • Der Anbieter ist der komplexeste Rezepttyp. Sie benötigen es nur, wenn Sie einen wiederverwendbaren Code erstellen, der eine globale Konfiguration erfordert.
  • Alle Spezialobjekte mit Ausnahme des Controllers werden über Werksrezepte definiert.

enter image description here

Und für Anfänger verstehen: - Dies kann den Anwendungsfall nicht korrigieren, aber auf hohem Niveau ist dies das, was für diese drei verwendet wird.

  1. Wenn Sie in angular Modul verwenden möchten, sollte die Konfigurationsfunktion als Anbieter erstellt werden
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
  1. Ajax Call oder Integrationen von Drittanbietern müssen ein Dienst sein .
  2. Für Datenmanipulationen erstellen Sie es als Fabrik

Für grundlegende Szenarien verhält sich Factory & Service gleich.

14

Hier ist ein Beispiel für einen Broilerplate-Code, den ich als Codevorlage für die Objektfabrik in AngularjS entwickelt habe. Ich habe ein Auto/eine Autofabrik als Beispiel verwendet, um dies zu veranschaulichen. Ermöglicht einen einfachen Implementierungscode in der Steuerung.

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

Hier ist ein einfacheres Beispiel. Ich verwende einige Bibliotheken von Drittanbietern, die ein "Position" -Objekt mit Längen- und Breitengraden erwarten, jedoch über unterschiedliche Objekteigenschaften. Ich wollte den Herstellercode nicht hacken, deshalb habe ich die "Position" -Objekte, die ich herumgereicht habe, angepasst.

    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

;

13
James Earlywine

Unter Verwendung dieser Seite und der Dokumentation (die sich offenbar seit meinem letzten Blick erheblich verbessert hat), habe ich die folgende echte (-ish) Weltdemo zusammengestellt, in der 4 der 5 Geschmacksrichtungen von verwendet werden Anbieter; Wert, Konstante, Fabrik und ausgewachsener Anbieter.

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

Arbeiten Demo .

12
net.uk.sweet

Diese Antwort befasst sich mit dem Thema/der Frage

wie Fabrik, Service und Konstante - sind syntaktische Zucker auf einem Versorgerrezept gerade?

ODER

wie Fabrik, Service und Anbieter intern ähnlich sind

im Grunde passiert was ist

Wenn Sie eine factory() ausführen, werden Sie function gesetzt, die im zweiten Argument an das $get des Providers übergeben wurde, und es wird zurückgegeben (provider(name, {$get:factoryFn })). alles, was Sie bekommen, ist provider, aber es gibt keine andere Eigenschaft/Methode als $get davon provider (bedeutet, dass Sie dies nicht konfigurieren können)

Quellcode der Fabrik

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

Wenn Sie eine service() erstellen, geben Sie an factory () ein function zurück, das das constructor einfügt (geben Sie die Instanz des Konstruktors zurück, den Sie in Ihrem Service angegeben haben), und geben Sie es zurück

Quellcode des Dienstes

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

Grundsätzlich erhalten Sie in beiden Fällen irgendwann einen Provider, der auf die von Ihnen angegebene Funktion gesetzt wird, aber Sie können alles andere als $ get angeben, wie Sie es ursprünglich in provider () für den Konfigurationsblock angegeben haben

12
A.B

Ich kenne eine Menge exzellenter Antworten, aber ich muss meine Erfahrungen mit der Verwendung teilen
1. service für die meisten Standardfälle
2. factory zum Erstellen des Dienstes für diese bestimmte Instanz

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

und mit:

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;
... 
11
nguyên

Basierend auf Speicherzwecken werden Controller nur instanziiert, wenn sie benötigt werden, und verworfen, wenn sie nicht benötigt werden. Aus diesem Grund bereinigt Angular jedes Mal, wenn Sie eine Route wechseln oder eine Seite neu laden, den aktuellen Controller. Dienste bieten jedoch die Möglichkeit, Daten während der gesamten Lebensdauer einer Anwendung zu speichern. Sie können auch auf konsistente Weise über verschiedene Controller hinweg verwendet werden.

Angular bietet drei Möglichkeiten, um unseren eigenen Service zu erstellen und zu registrieren.

1) Fabrik

2) Service

3) Anbieter

Factory: Eine Factory ist eine einfache Funktion, mit der Sie vor dem Erstellen des Objekts eine Logik hinzufügen können. Es gibt das erstellte Objekt zurück.

Es ist nur eine Sammlung von Funktionen wie eine Klasse. Daher kann es in verschiedenen Controllern instanziiert werden, wenn Sie es mit der Konstruktorfunktion verwenden.

Service: Ein Service ist eine Konstruktorfunktion, die das Objekt mit einem neuen Schlüsselwort erstellt. Mit diesem Schlüsselwort können Sie einem Serviceobjekt Eigenschaften und Funktionen hinzufügen. Im Gegensatz zur Fabrik gibt es nichts zurück.

Es ist ein Singleton-Objekt. Verwenden Sie diese Option, wenn Sie ein einzelnes Objekt in der Anwendung freigeben müssen. Zum Beispiel authentifizierte Benutzerdetails.

Provider: Mit einem Provider wird ein konfigurierbares Serviceobjekt erstellt. Mit der Funktion $ get () wird ein Wert zurückgegeben.

Wenn Sie eine modulweise Konfiguration für Ihr Serviceobjekt vornehmen müssen, bevor Sie es zur Verfügung stellen können.

Führen Sie den folgenden Code aus, und sehen Sie sich die Ausgabe an.

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

Etwas zu spät zur Party. Ich fand dies jedoch hilfreicher für diejenigen, die die Entwicklung von Angular JS Custom Services mithilfe von Factory-, Service- und Providermethoden erlernen möchten (oder Klarheit haben möchten).

Ich bin auf dieses Video gestoßen, in dem die Fabrik-, Dienstleistungs- und Anbietermethoden für die Entwicklung von AngularJS Custom Services klar erläutert werden:

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

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

Der hier veröffentlichte Code wird direkt aus der obigen Quelle kopiert, um den Lesern zu helfen.

Der Code für den benutzerdefinierten Dienst auf Factory-Basis lautet wie folgt (dies gilt sowohl für die Synchronisierungs- als auch für die Asynchronisierungsversion zusammen mit dem Aufrufen des http-Diensts):

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

Der Code für die "Service" -Methode für benutzerdefinierte Services (diese Methode ähnelt der "Factory" -Methode, unterscheidet sich jedoch von der Syntaxansicht):

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

}]);

Der Code für die "Provider" -Methode für benutzerdefinierte Dienste (dies ist erforderlich, wenn Sie einen Dienst entwickeln möchten, der konfiguriert werden kann):

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

Schließlich die Benutzeroberfläche, die mit einem der oben genannten Dienste funktioniert:

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

Zur Verdeutlichung können Sie in der AngularJS-Quelle sehen, dass ein Dienst nur die Factory-Funktion aufruft, die wiederum die Provider-Funktion aufruft:

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

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

Lassen Sie uns die drei Möglichkeiten des Umgangs mit Geschäftslogik in AngularJS auf einfache Weise diskutieren: (Inspiriert von Yaakovs Coursera AngularJS-Kurs)

SERVICE:

Syntax:

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>

Leistungsmerkmale:

  1. Lazily Instantiated : Wenn es nicht injiziert wird, wird es niemals instanziiert. Um es zu verwenden, muss es in ein Modul injiziert werden.
  2. Singleton : Wenn es in mehrere Module injiziert wird, haben alle Zugriff auf nur eine bestimmte Instanz. Aus diesem Grund ist es sehr praktisch, Daten zwischen verschiedenen Controllern auszutauschen.

FACTORY

Schauen wir uns zuerst die Syntax an:

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

Verwenden Sie jetzt die beiden oben im Controller:

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

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

Merkmale der Fabrik:

  1. Folgt dem Factory Design Pattern. Die Fabrik ist ein zentraler Ort, an dem neue Objekte oder Funktionen entstehen.
  2. Produziert nicht nur Singleton, sondern anpassbare Dienste.
  3. Die .service() -Methode ist eine Factory -Methode, die immer dieselbe Art von Dienst erzeugt, nämlich einen Singleton, und dessen Verhalten nicht auf einfache Weise konfiguriert werden kann. Diese .service() -Methode wird normalerweise als Verknüpfung für etwas verwendet, für das keinerlei Konfiguration erforderlich ist.

PROVIDER

Schauen wir uns zunächst noch einmal die Syntax an:

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

}

Merkmale des Anbieters:

  1. Provider ist die flexibelste Methode zum Erstellen von Diensten in Angular.
  2. Wir können nicht nur eine Factory erstellen, die dynamisch konfigurierbar ist, sondern zum Zeitpunkt der Verwendung der Factory mit der Provider-Methode können wir die Factory nur einmal beim Bootstrapping unserer gesamten Anwendung benutzerdefiniert konfigurieren.
  3. Die Fabrik kann dann in der gesamten Anwendung mit benutzerdefinierten Einstellungen verwendet werden. Mit anderen Worten, wir können diese Factory konfigurieren, bevor die Anwendung gestartet wird. Tatsächlich wird in der Dokumentation zu angular erwähnt, dass die Provider-Methode tatsächlich hinter den Kulissen ausgeführt wird, wenn wir unsere Services mit den Methoden .service oder .factory konfigurieren.
  4. Der $get ist eine Funktion, die direkt an die Provider-Instanz angehängt ist. Diese Funktion ist eine Fabrik Funktion. Mit anderen Worten, es ist genau so, wie wir es verwenden, um für die .factory -Methode bereitzustellen. In dieser Funktion erstellen wir unseren eigenen Service. Diese $get Eigenschaft, das ist eine Funktion, die den Provider zum Provider macht. AngularJS erwartet vom Provider eine Eigenschaft $ get, deren Wert eine Funktion ist, die Angular als Factory-Funktion behandelt. Aber was Das Besondere an diesem gesamten Provider-Setup ist die Tatsache, dass wir innerhalb des Service Providers ein config -Objekt bereitstellen können. Dies bringt normalerweise Standardeinstellungen mit sich, die wir später in dem Schritt, in dem wir die gesamte Anwendung konfigurieren können, überschreiben können.
9
Pritam Banerjee

Factory: Die Factory, in der Sie tatsächlich ein Objekt innerhalb der Factory erstellen und es zurückgeben.
service: Der Dienst, für den Sie gerade eine Standardfunktion haben, die das Schlüsselwort this verwendet, um die Funktion zu definieren.
provider: Der Anbieter, für den Sie ein $ get definieren, kann verwendet werden, um das Objekt abzurufen, das die Daten zurückgibt.

7
MR Kesavan

Im Wesentlichen sind Provider, Factory und Service alle Services. Eine Factory ist ein Sonderfall eines Service, wenn Sie lediglich eine $ get () - Funktion benötigen, mit der Sie weniger Code schreiben können.

Die Hauptunterschiede zwischen Services, Fabriken und Providern liegen in ihrer Komplexität. Services sind die einfachste Form, Fabriken sind etwas robuster und Provider können zur Laufzeit konfiguriert werden.

Hier ist eine Zusammenfassung der Verwendungszeiten:

Factory: Der von Ihnen angegebene Wert muss auf der Grundlage anderer Daten berechnet werden.

Service: Sie geben ein Objekt mit Methoden zurück.

Provider: Sie möchten in der Konfigurationsphase das Objekt konfigurieren können, das erstellt werden soll, bevor es erstellt wird. Verwenden Sie den Provider hauptsächlich in der App-Konfiguration, bevor die App vollständig initialisiert wurde.

7
eGhoul

1.Dienste sind Singleton-Objekte, die bei Bedarf erstellt und erst am Ende des Anwendungslebenszyklus (beim Schließen des Browsers) bereinigt werden. Controller werden zerstört und bereinigt, wenn sie nicht mehr benötigt werden.

2.Die einfachste Methode zum Erstellen eines Dienstes ist die Verwendung der factory () -Methode. Mit der factory () -Methode können wir einen Service definieren, indem wir ein Objekt zurückgeben, das Servicefunktionen und Servicedaten enthält. In der Service-Definitionsfunktion platzieren wir unsere injizierbaren Services, z. B. $ http und $ 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; });

Verwendung der Fabrik () in unserer App

Es ist einfach, die Factory in unserer Anwendung zu verwenden, da wir sie zur Laufzeit einfach dort einfügen können, wo wir sie benötigen.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Mit der service () -Methode hingegen können wir einen Service erstellen, indem wir eine Konstruktorfunktion definieren. Wir können ein prototypisches Objekt verwenden, um unseren Service zu definieren, anstatt ein Javascript-Rohobjekt. Ähnlich wie bei der factory () -Methode werden auch die injizierbaren Werte in der Funktionsdefinition festgelegt.
  2. Die unterste Ebene zum Erstellen eines Dienstes ist die Verwendung der deliver () -Methode. Dies ist die einzige Möglichkeit, einen Dienst zu erstellen, den wir mit der Funktion .config () konfigurieren können. Im Gegensatz zu den vorherigen Methoden legen wir die injizierbaren Dateien in einer definierten this. $ Get () -Funktionsdefinition fest.
4