Pytanie AngularJS: Service vs provider vs factory


Jakie są różnice między a Service, Provider i Factory w AngularJS?


3167
2018-03-27 17:59


pochodzenie


Zauważyłem, że wszystkie terminy kątowe były zastraszające dla początkujących. Zaczęliśmy od tego kodu, który był nieco łatwiejszy do zrozumienia dla naszych programistów podczas uczenia się Angular demisx.github.io/angularjs/2014/09/14/.... Mam nadzieję, że to pomoże także Twojemu zespołowi. - demisx
Moim zdaniem najlepszym sposobem na zrozumienie różnicy jest wykorzystanie własnej dokumentacji Angular: docs.angularjs.org/guide/providers jest bardzo dobrze wytłumaczony i używa osobliwego przykładu, aby pomóc ci go zrozumieć. - Rafael Merlin
@Blaise Dziękujemy! Zgodnie z moim komentarzem w poście, celowo go opuściłem, ponieważ 99% przypadków użycia z mojego doświadczenia może być z powodzeniem obsługiwane za pośrednictwem service.factory. Nie chciałem dalej komplikować tego tematu. - demisx
Uważam, że ta dyskusja jest również bardzo przydatna stackoverflow.com/questions/18939709/... - Anand Gupta
Oto kilka dobrych odpowiedzi o tym, jak services, factories i providers Prace. - Mistalis


Odpowiedzi:


Z listy mailingowej AngularJS mam niesamowita nić to wyjaśnia serwis kontra fabryka a dostawcę i ich użycie wtryskowe. Kompilowanie odpowiedzi:

Usługi

Składnia: module.service( 'serviceName', function ); 
Wynik: Podczas deklarowania serviceName jako argumentu do wstrzykiwania otrzymasz instancję funkcji. Innymi słowy  new FunctionYouPassedToService().

Fabryki

Składnia: module.factory( 'factoryName', function ); 
Wynik: Podczas deklarowania fabrykiName jako argumentu do wstrzykiwania dostaniesz wartość zwracana przez wywołanie odwołania funkcji przekazanego do module.factory.

Dostawcy

Składnia: module.provider( 'providerName', function ); 
Wynik: Podczas deklarowania providerName jako argumentu do wstrzykiwania otrzymasz pomoc  (new ProviderFunction()).$get(). Funkcja konstruktora jest tworzona przed wywołaniem metody $ get - ProviderFunction jest odniesieniem do funkcji przekazanym do module.provider.

Dostawcy mają tę zaletę, że można je skonfigurować podczas fazy konfiguracji modułu.

Widzieć tutaj dla podanego kodu.

Oto świetne dodatkowe wyjaśnienie Misko:

provide.value('a', 123);

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

W takim przypadku wtryskiwacz po prostu zwraca wartość taką jaka jest. Ale co, jeśli chcesz obliczyć wartość? Następnie użyj fabryki

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

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

Więc factory jest funkcją odpowiedzialną za tworzenie wartości. Zauważ, że funkcja fabryczna może żądać innych zależności.

Ale co, jeśli chcesz być bardziej OO i mieć klasę o nazwie Greeter?

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

Następnie, aby utworzyć instancję, musisz napisać

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

Wtedy moglibyśmy poprosić o "powitanie" w takim kontrolerze

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

Ale to jest zbyt rozwlekłe. Krótszy sposób napisania tego byłoby provider.service('greeter', Greeter);

Ale co jeśli chcemy skonfigurować Greeter klasa przed wstrzyknięciem? Potem moglibyśmy napisać

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

Następnie możemy to zrobić:

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

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

Na marginesie, service, factory, i value wszystkie pochodzą od dostawcy.

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

2803
2017-07-30 10:20



Zobacz też stackoverflow.com/a/13763886/215945 która omawia różnice między usługą a fabryką. - Mark Rajcok
W edycji 611 dodano użycie kątowych stałych i wartości. Aby zademonstrować różnice w innych już pokazanych. jsbin.com/ohamub/611/edit - Nick
Chociaż usługa jest wywoływana przez utworzenie instancji funkcji. W rzeczywistości jest on tworzony tylko raz na iniektor, co sprawia, że ​​przypomina singleton.docs.angularjs.org/guide/dev_guide.services.creating_services - angelokh
Ten przykład może być niewiarygodny, jeśli użyjemy jasnego praktycznego przykładu. Zgubiłem się, próbując dowiedzieć się, o co chodzi toEqual i greeter.Greet jest. Dlaczego nie użyć czegoś bardziej realnego i możliwego do zidentyfikowania? - Kyle Pennell
Używanie funkcji expect () jest złym wyborem, aby coś wyjaśnić. Użyj kodu świata realnego następnym razem. - Craig


JS Fiddle Demo

Przykład "Witaj świecie" z 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>


797
2018-05-15 15:53



Nie robi this zmienić kontekst w $get funkcjonować? - nie odwołujesz się już do instancji dostawcy w tej funkcji. - Nate-Wilkins
@Nate: this nie zmienia kontekstu, ponieważ to, co się nazywa, jest new Provider(). $ get (), gdzie Provider jest funkcją, do której przekazywane są app.provider. To znaczy, że $get() jest nazywany jako metoda na skonstruowanym Provider, więc this będzie odnosić się do Provider jak sugeruje przykład. - Brandon
@ Brandon Ohh ok, to jest miłe wtedy. Mylące na pierwszy rzut oka - dzięki za wyjaśnienie! - Nate-Wilkins
Dlaczego dostaję Unknown provider: helloWorldProvider <- helloWorld podczas uruchamiania tego lokalnie? Komentując to, ten sam błąd dla pozostałych 2 przykładów. Czy jest jakaś ukryta konfiguracja dostawcy? (Angular 1.0.8) - Znaleziono: stackoverflow.com/questions/12339272/... - Antoine
Jest powód, dla którego @Antoine dostaje błąd "Nieznany dostarcz: helloWorldProvider", ponieważ w twoim kodzie .config używasz "helloWorldProvider", ale kiedy definiujesz dostawcę w myApp.provider ("helloWorld", function ()), używasz 'Witaj świecie'? Innymi słowy, w twoim kodzie konfiguracyjnym, w jaki sposób kątowy wie, że odnosisz się do dostawcy helloWorld? Dzięki - jmtoung


TL; DR 

1) Kiedy używasz Fabryka tworzysz obiekt, dodajesz do niego właściwości, a następnie zwraca ten sam obiekt. Po przejściu tej fabryki do kontrolera, te właściwości obiektu będą teraz dostępne w tym sterowniku przez fabrykę.

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) Kiedy używasz UsługaAngularJS tworzy instancję za kulisami za pomocą słowa kluczowego "new". Z tego powodu dodasz właściwości do "this", a usługa zwróci "this". Kiedy przekażesz usługę do kontrolera, te właściwości na "tej" będą teraz dostępne na tym kontrolerze za pośrednictwem twojej usługi.

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

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



3)  Dostawcy to jedyna usługa, którą możesz przekazać do swojej funkcji .config (). Użyj dostawcy, aby udostępnić moduł dla całego obiektu usługi przed udostępnieniem go.

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) Fabryka 
Fabryki są najpopularniejszym sposobem tworzenia i konfigurowania usługi. Naprawdę niewiele więcej niż to, co powiedział TL; DR. Wystarczy utworzyć obiekt, dodać do niego właściwości, a następnie zwrócić ten sam obiekt. Następnie, po przejściu fabryki do kontrolera, te właściwości obiektu będą teraz dostępne w tym sterowniku przez fabrykę. Bardziej rozbudowany przykład znajduje się poniżej.

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

Teraz wszelkie właściwości, które przywiązujemy do "usługi" będą dostępne dla nas, kiedy przekazujemy "myFactory" do naszego kontrolera.

Dodajmy teraz zmienne "prywatne" do naszej funkcji wywołania zwrotnego. Nie będą one bezpośrednio dostępne ze sterownika, ale ostatecznie stworzymy niektóre metody pobierania / ustawiania w "usłudze", aby w razie potrzeby móc zmienić te "prywatne" zmienne.

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

Tutaj zauważysz, że nie przypisujemy tych zmiennych / funkcji do "usługi". Po prostu je tworzymy, aby później móc z nich korzystać lub modyfikować.

  • baseUrl to podstawowy adres URL wymagany przez interfejs API iTunes
  • _artist to artysta, którego szukamy
  • _finalUrl to ostateczny i w pełni zbudowany adres URL, do którego nawiążemy połączenie z iTunes
  • makeUrl to funkcja, która stworzy i zwróci nasz przyjazny adres URL w iTunes.

Teraz, gdy nasze pomocnicze / prywatne zmienne i funkcje są na miejscu, dodajmy niektóre właściwości do obiektu "usługi". Wszystko, co umieścimy w "usłudze" może być bezpośrednio użyte w jakimkolwiek kontrolerze, przez który przechodzimy "myFactory".

Zamierzamy stworzyć metody setArtist i getArtist, które po prostu zwrócą lub ustawią artystę. Zamierzamy również stworzyć metodę, która wywoła interfejs API iTunes z naszym utworzonym adresem URL. Ta metoda zwróci obietnicę, która wypełni się po powrocie danych z interfejsu API iTunes. Jeśli nie masz dużego doświadczenia w korzystaniu z obietnic w AngularJS, bardzo polecam wykonanie głębokiego nurkowania.

Poniżej setArtist akceptuje artystę i pozwala ustawić artystę. getArtist zwraca artystę. callItunes najpierw wywołuje makeUrl () w celu zbudowania adresu URL, którego użyjemy z naszym żądaniem $ http. Następnie ustawia obiekt obietnicy, wysyła żądanie HTTP z naszym końcowym adresem URL, a następnie, ponieważ $ http zwraca obietnicę, jesteśmy w stanie wywołać .success lub .error po naszej prośbie. Następnie rozwiązujemy naszą obietnicę danymi z iTunes lub odrzucamy ją z komunikatem "Wystąpił błąd".

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

Teraz nasza fabryka jest kompletna. Możemy teraz wprowadzić "myFactory" do dowolnego kontrolera, a następnie będziemy mogli wywoływać nasze metody, które przypisaliśmy do naszego obiektu usługi (setArtist, getArtist i 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);
      })
  }
});

W powyższym kontrolerze wstrzykiwamy usługę "myFactory". Następnie ustawiamy właściwości w naszym obiekcie $ scope na dane z "myFactory". Jedynym trudnym kodem powyżej jest to, że nigdy wcześniej nie zajmowałeś się obietnicami. Ponieważ callItunes zwraca obietnicę, jesteśmy w stanie użyć metody .then () i ustawić tylko $ scope.data.artistData, gdy nasza obietnica zostanie spełniona z danymi iTunes. Zauważysz, że nasz kontroler jest bardzo "cienki" (jest to dobra praktyka kodowania). Wszystkie nasze logiczne i trwałe dane znajdują się w naszej usłudze, a nie w naszym kontrolerze.

2) Usługa 
Być może najważniejszą rzeczą, która należy wiedzieć, kiedy tworzy się usługę, jest utworzenie instancji za pomocą słowa kluczowego "new". Dla ciebie guru JavaScriptu powinno ci to dać dużą wskazówkę co do natury kodu. Dla tych z ograniczonym pochodzeniem w JavaScript lub dla tych, którzy nie są zbyt obeznani z słowem kluczowym "new", przyjrzyjmy się podstawom JavaScript, które ostatecznie pomogą nam zrozumieć naturę usługi.

Aby naprawdę zobaczyć zmiany, które występują podczas wywoływania funkcji za pomocą słowa kluczowego "new", stwórzmy funkcję i wywołajmy ją za pomocą słowa kluczowego "new", a następnie pokażmy, co robi interpreter, gdy widzi słowo kluczowe "new". Wyniki końcowe będą oba takie same.

Najpierw utwórzmy naszego Konstruktora.

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

Jest to typowa funkcja konstruktora JavaScript. Teraz, gdy wywołujemy funkcję Person za pomocą słowa kluczowego "new", "this" będzie związane z nowo utworzonym obiektem.

Dodajmy teraz metodę do prototypu naszej Osoby, aby była dostępna na każdym egzemplarzu klasy "Osoby".

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

Teraz, ponieważ umieściliśmy funkcję sayName na prototypie, każde wystąpienie Osoby będzie mogło wywołać funkcję sayName w celu ostrzeżenia tej nazwy instancji.

Teraz, gdy mamy funkcję konstruktora Person i funkcję sayName na jego prototypie, stwórzmy instancję Person, a następnie wywołaj funkcję sayName.

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

Zatem cały kod kodujący konstruktora Person, dodawanie funkcji do jego prototypu, tworzenie instancji Person, a następnie wywoływanie funkcji na jej prototypie wygląda następująco.

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’

Teraz spójrzmy na to, co się dzieje, kiedy używasz słowa kluczowego "new" w JavaScript. Pierwszą rzeczą, którą należy zauważyć, jest to, że po użyciu "nowego" w naszym przykładzie możemy wywołać metodę (sayName) na "tyler" tak, jakby był obiektem - to dlatego, że tak jest. Po pierwsze, wiemy, że nasz konstruktor Person zwraca obiekt, niezależnie od tego, czy widzimy go w kodzie, czy nie. Po drugie, wiemy, że ponieważ nasza funkcja sayName znajduje się na prototypie, a nie bezpośrednio na instancji Person, obiekt zwracany przez funkcję Person musi delegować do swojego prototypu w przypadku nieudanych wyszukiwań. Mówiąc prostszymi słowami, gdy wywołujemy tyler.sayName (), tłumacz mówi: "OK, zamierzam spojrzeć na właśnie utworzony obiekt" tyler ", zlokalizować funkcję sayName, a następnie ją wywołać. Zaczekaj chwilę, nie widzę tego tutaj - wszystko co widzę to imię i wiek, pozwól mi sprawdzić prototyp. Tak, wygląda na prototyp, pozwól mi to nazwać. ".

Poniżej znajduje się kod, w jaki sposób można myśleć o tym, co słowo kluczowe "nowe" faktycznie robi w JavaScript. Jest to w zasadzie przykład kodu powyższego akapitu. Umieściłem "widok tłumacza" lub sposób, w jaki interpretator widzi kod wewnątrz nut.

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

Teraz, mając tę ​​wiedzę na temat znaczenia słowa kluczowego "new" w JavaScript, stworzenie usługi w AngularJS powinno być łatwiejsze do zrozumienia.

Najważniejszą rzeczą do zrozumienia podczas tworzenia usługi jest świadomość, że Usługi są tworzone za pomocą "nowego" słowa kluczowego. Łącząc tę ​​wiedzę z naszymi przykładami powyżej, powinieneś teraz zauważyć, że będziesz przywiązywać swoje właściwości i metody bezpośrednio do "tego", które następnie zostaną zwrócone z samej Usługi. Rzućmy okiem na to w akcji.

W przeciwieństwie do tego, co pierwotnie zrobiliśmy w przykładzie Factory, nie musimy tworzyć obiektu, a następnie zwracać ten obiekt, ponieważ, jak wspomniano wiele razy wcześniej, użyliśmy słowa kluczowego "new", więc interpreter utworzy ten obiekt, zleci to to prototyp, a następnie zwróć go za nas bez konieczności wykonywania pracy.

Po pierwsze, stwórzmy naszą "prywatną" i pomocniczą funkcję. Powinno to wyglądać bardzo znajomo, ponieważ zrobiliśmy dokładnie to samo z naszą fabryką. Nie wyjaśniam, co tutaj robi każda linia, ponieważ zrobiłem to na przykładzie fabryki, jeśli jesteś zdezorientowany, przeczytaj ponownie przykład fabryki.

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

Teraz dołączymy wszystkie nasze metody, które będą dostępne w naszym kontrolerze do "tego".

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

});

Teraz podobnie jak w naszej fabryce, setArtist, getArtist i callItunes będą dostępne w dowolnym kontrolerze, w którym przekazujemy myService. Oto kontroler myService (który jest prawie dokładnie taki sam jak nasz kontroler fabryczny).

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

Tak jak wspomniałem wcześniej, kiedy naprawdę zrozumiesz, co "nowe", usługi są prawie identyczne z fabrykami w AngularJS.

3) Dostawca

Najważniejszą rzeczą do zapamiętania na temat Providers jest to, że są one jedyną usługą, którą można przekazać do części app.config aplikacji. Ma to ogromne znaczenie, jeśli chcesz zmienić część obiektu usługi, zanim będzie dostępna w innych aplikacjach. Chociaż bardzo podobne do usług / fabryk, istnieje kilka różnic, które omówimy.

Najpierw skonfigurowaliśmy naszego dostawcę w sposób podobny do naszego serwisu i fabryki. Poniższe zmienne są naszą "prywatną" i pomocniczą funkcją.

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

* Ponownie, jeśli jakakolwiek część powyższego kodu jest myląca, zajrzyj do sekcji Factory, gdzie wyjaśnię, co to wszystko robi, dokładniej.

Możesz myśleć o dostawcach jako o trzech sekcjach. Pierwsza sekcja to "prywatne" zmienne / funkcje, które zostaną zmodyfikowane / ustawione później (pokazane powyżej). Druga sekcja to zmienne / funkcje, które będą dostępne w twojej funkcji app.config i dlatego można je zmieniać, zanim będą dostępne nigdzie indziej (również pokazane powyżej). Należy pamiętać, że te zmienne muszą być dołączone do słowa kluczowego "to". W naszym przykładzie tylko "thingFromConfig" będzie dostępne do zmiany w pliku app.config. Trzecia sekcja (pokazana poniżej) to wszystkie zmienne / funkcje, które będą dostępne w kontrolerze po przejściu do usługi "myProvider" w tym konkretnym kontrolerze.

Podczas tworzenia usługi z dostawcą jedynymi właściwościami / metodami, które będą dostępne w kontrolerze, są te właściwości / metody, które są zwracane z funkcji $ get (). Poniższy kod umieszcza $ get na "tym" (który, jak wiemy, zostanie ostatecznie zwrócony z tej funkcji). Teraz funkcja $ get zwraca wszystkie metody / właściwości, które chcemy udostępnić w kontrolerze. Oto przykład kodu.

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

Teraz pełny kod dostawcy wygląda następująco

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

Teraz, podobnie jak w naszej fabryce i usłudze, setArtist, getArtist i callItunes będą dostępne w sterowniku, do którego przekazujemy myProvider. Oto kontroler myProvider (który jest prawie dokładnie taki sam jak nasz kontroler fabryczny / serwisowy).

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

Jak już wcześniej wspomniano, cały sens tworzenia usługi za pomocą Provider polega na możliwości zmiany niektórych zmiennych za pomocą funkcji app.config, zanim ostateczny obiekt zostanie przekazany do reszty aplikacji. Zobaczmy przykład tego.

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

Teraz możesz zobaczyć, jak "thingFromConfig" jest pustym ciągiem w naszym dostawcy, ale gdy pojawi się w DOM, będzie to "To zdanie zostało ustawione ...".


619
2017-12-24 13:15



Jedyną brakującą częścią tego doskonałego zapisu jest względna zaleta korzystania z usługi nad fabryką; co jest jasno wyjaśnione w zaakceptowanej odpowiedzi Liora - infinity
FWIW (może nie za dużo), tutaj jest blogger, który zajmuje się Angularem i nie lubi providerProvider codeofrob.com/entries/you-have-ruined-javascript.html - barlop
Punchlina "guru JavaScriptu" była przebiegła. : D Myślę, że ta odpowiedź bardzo wyjaśnia. Znakomicie napisane. - amarmishra
Twój TLDR potrzebuje TLDR. - JensB
@ JensB tl; dr - Learn React. - Tyler McGinnis


Wszystkie usługi są singletons; otrzymują instancję raz na aplikację. Oni mogą być dowolnego rodzaju, czy jest to prymitywny, literalny obiekt, funkcja, czy nawet instancja typu niestandardowego.

The value, factory, service, constant, i provider metody to wszyscy dostawcy. Uczą Injectora, jak tworzyć instancje Usług.

Najbardziej obszerny, ale i najbardziej kompleksowy jest Dostawcą   Przepis. The pozostałe cztery typy receptur - wartość, fabryka, serwis i   Stała - to tylko cukier syntaktyczny na recepturze dostawcy.

  • The Wartość Przepis jest najprostszym przypadkiem, w którym samodzielnie tworzysz Usługę i zapewniasz jej Utworzona wartość do wtryskiwacza.
  • The Przepis fabryczny daje injektorowi funkcję fabryczną, którą wywołuje, gdy musi utworzyć instancję usługi. Po wywołaniu, funkcja fabryczna tworzy i zwraca instancję usługi. Zależności usługi są wprowadzane jako argumenty funkcji. Używanie tego przepisu dodaje następujące umiejętności:
    • Możliwość korzystania z innych usług (mają zależności)
    • Inicjalizacja usługi
    • Opóźniona / leniwy inicjalizacja
  • The Przepis usługowy jest prawie taka sama jak receptura Factory, ale tutaj Injector wywołuje a konstruktor z nowym operatorem zamiast funkcją fabryczną.
  • The Przepis dostawcy jest zwykle przesada. Dodaje jeszcze jedną warstwę pośrednią, umożliwiając konfigurację procesu tworzenia fabryki.

Powinieneś używać przepisu dostawcy tylko wtedy, gdy chcesz ujawnić interfejs API   dla całej aplikacji, która musi być wykonana przed   uruchamianie aplikacji. Zazwyczaj jest to interesujące tylko do wielokrotnego użytku   usługi, których zachowanie może nieznacznie różnić się między   Aplikacje.


506
2018-02-01 12:58



Więc serwis i fabryka są w zasadzie takie same? Korzystanie z jednego z innych zapewnia tylko alternatywną składnię? - Matt
@Matt, tak, usługa jest zwięzła, gdy masz już własną funkcję, którą chcesz eksponować jako usługę. From docs: myApp.factory ('unicornLauncher', ["apiToken", funkcja (apiToken) {return new UnicornLauncher (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]); - janek
@joshperry Jako początkujący przez jakiś czas szukałem różnicy między usługą a fabryką. Zgadzam się, to najlepsza odpowiedź w historii! Zrozumiałbym, że usługa jest klasą usług (np. Klasa kodera / dekodera), która może mieć pewne prywatne właściwości. A fabryka dostarcza zestaw bezpaństwowych metod pomocniczych. - stanleyxu2005
Przykłady podane w innych odpowiedziach powyżej nie wyjaśniają w sposób jednoznaczny zasadniczej różnicy między usługami a dostawcami, które są wprowadzane w momencie, gdy te przepisy są tworzone. - Ashish Singh


Zrozumienie fabryki, serwisu i dostawcy AngularJS

Wszystkie te są używane do udostępniania wielokrotnego użytku obiektów singleton. Pomaga w udostępnianiu kodu wielokrotnego użytku w aplikacji / różnych komponentach / modułach.

Z Dokumentów Serwis / Fabryka:

  • Lazily powstały - Angular tylko tworzy instancję usługi / fabryki, gdy od tego zależy komponent aplikacji.
  • Singletons - Każdy składnik   zależne od usługi otrzymuje odniesienie do pojedynczej instancji   generowane przez fabrykę usług.

Fabryka

Fabryka jest funkcją, w której można manipulować / dodawać logikę przed utworzeniem obiektu, a następnie nowo utworzony obiekt zostaje zwrócony.

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

Stosowanie

Może to być po prostu zbiór funkcji takich jak klasa. W związku z tym można go utworzyć w różnych kontrolerach podczas wprowadzania go do funkcji kontrolera / fabryki / dyrektywy. Jest tworzony tylko raz dla każdej aplikacji.

Usługa

Po prostu patrząc na usługi pomyśl o prototypie macierzy. Usługa to funkcja, która tworzy nowy obiekt za pomocą słowa kluczowego "nowy". Możesz dodać właściwości i funkcje do obiektu usługi za pomocą thissłowo kluczowe. W przeciwieństwie do fabryki, nie zwraca niczego (zwraca obiekt zawierający metody / właściwości).

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

Stosowanie

Użyj go, gdy chcesz udostępnić pojedynczy obiekt w całej aplikacji. Na przykład uwierzytelnione dane użytkownika, udostępniane metody / dane, funkcje narzędziowe itp.

Dostawca

Dostawca służy do tworzenia konfigurowalnego obiektu usługi. Możesz skonfigurować ustawienia usługi z funkcji konfiguracji. Zwraca wartość za pomocą znaku $get() funkcjonować. The $get funkcja zostaje wykonana w fazie biegu w kanciastej.

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

Stosowanie

Kiedy musisz dostarczyć konfigurację modułową dla obiektu usługi przed udostępnieniem, np. Załóżmy, że chcesz ustawić adres URL interfejsu API na podstawie swojego środowiska, takiego jak dev, stage lub prod

UWAGA 

Tylko dostawca będzie dostępny w fazie konfiguracji kątowej, natomiast   usługa i fabryka nie są.

Mam nadzieję, że to wyjaśniło twoje zrozumienie Fabryka, serwis i dostawca.


221
2017-11-14 06:25



Co powinienem zrobić, gdybym chciał mieć usługę z konkretnym interfejsem, ale miałbym dwie różne implementacje i wstrzyknąć każdy do kontrolera, ale przywiązany do różnych stanów za pomocą routera ui? na przykład nawiązywać połączenia zdalne w jednym stanie, ale zapisywać w pamięci lokalnej zamiast w innym. Doktorzy dostawcy mówią, żeby ich użyć only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications, więc nie brzmi to możliwe, prawda? - qix


Dla mnie objawienie nastąpiło, gdy zdałem sobie sprawę, że wszystkie działają w ten sam sposób: przez prowadzenie czegoś pewnego razu, przechowując wartość, którą otrzymują, a następnie kaszlą ta sama przechowywana wartość kiedy się odwołuje przez iniekcja zależności.

Powiedzmy, że mamy:

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

Różnica między tymi trzema polega na tym, że:

  1. aprzechowywana wartość pochodzi z działania fn.
  2. bZ tego pochodzi wartość przechowywana newing fn.
  3. cPrzechowywana wartość pochodzi z pierwszego pobrania instancji przez newing fn, a następnie uruchomienie $get metoda instancji.

Co oznacza, że ​​wewnątrz AngularJS znajduje się coś takiego jak obiekt pamięci podręcznej, którego wartość każdego zastrzyku jest przypisana tylko raz, gdy zostały one po raz pierwszy wstrzyknięte i gdzie:

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

Właśnie dlatego używamy this w usługach i zdefiniuj a this.$get w dostawcach.


190
2017-07-22 11:39



Najbardziej podoba mi się ta odpowiedź. Celem ich wszystkich jest zapewnienie dostępu do obiektu w razie potrzeby poprzez DI. Zwykle dobrze ci idzie factorys. Jedyny powód services istnieją takie języki jak: CoffeeScript, TypeScript, ES6 itd., więc możesz użyć ich składni klasowej. Potrzebujesz providers tylko jeśli twój moduł jest używany w kilku aplikacjach z różnymi ustawieniami przy użyciu app.config(). Jeśli twoja usługa jest czystym singletonem lub jest w stanie stworzyć instancje czegoś tylko zależy od twojej implementacji. - Andreas Linnert


Usługa kontra dostawca kontra fabryka:

Próbuję to uprościć. Chodzi o podstawową koncepcję JavaScript.

Po pierwsze, porozmawiajmy o tym usługi w AngularJS!

Co to jest usługa: W AngularJS, Usługa jest niczym innym jak pojedynczym obiektem JavaScript, który może przechowywać pewne przydatne metody lub właściwości. Ten obiekt singleton jest tworzony na podstawie aplikacji ngApp (Angular app) i jest udostępniany wszystkim kontrolerom w ramach bieżącej aplikacji. Gdy Angularjs tworzy instancję obiektu usługi, rejestruje ten obiekt usługi z unikalną nazwą usługi. Tak więc za każdym razem, gdy potrzebujemy instancji usługi, Angular przeszukuje rejestr dla tej nazwy usługi i zwraca odwołanie do obiektu usługi. Tak, że możemy wywołać metodę, dostęp do właściwości itp. Na obiekcie usługi. Możesz mieć pytanie, czy możesz również umieścić właściwości, metody na obiekcie obiektowym kontrolerów! Dlaczego więc potrzebujesz obiektu usługi? Odpowiedzi są następujące: usługi są współużytkowane przez wiele kontrolerów. Jeśli umieścisz pewne właściwości / metody w obiekcie zakresu kontrolera, będzie on dostępny tylko dla bieżącego zakresu. Ale kiedy zdefiniujesz metody, właściwości na obiekcie usługi, będzie on dostępny globalnie i będzie dostępny w dowolnym zakresie kontrolera poprzez wstrzykiwanie tej usługi.

Jeśli więc istnieją trzy zakresy kontrolerów, niech to będzie kontroler A, kontroler B i kontrolerC, wszystkie będą udostępniać tę samą instancję usługi.

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

Jak stworzyć usługę?

AngularJS udostępnia różne metody rejestrowania usługi. Tutaj skoncentrujemy się na trzech metodach fabryki (..), usłudze (..), dostawcy (..);

Użyj tego linku, aby uzyskać odniesienie do kodu

Funkcja fabryczna:

Możemy zdefiniować funkcję fabryczną, jak poniżej.

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

AngularJS zapewnia "factory (" serviceName ", fnFactory)" metoda, która pobiera dwa parametry, serviceName i funkcję JavaScript. Angular tworzy instancję usługi, wywołując funkcję fnFactory () takie jak poniżej.

var serviceInstace = fnFactory();

Przekazana funkcja może zdefiniować obiekt i zwrócić ten obiekt. AngularJS przechowuje po prostu odwołanie do tego obiektu do zmiennej, która jest przekazywana jako pierwszy argument. Wszystko, co zostanie zwrócone z fnFactory, będzie powiązane z serviceInstance. Zamiast zwracanego obiektu możemy zwrócić także funkcję, wartości itp. Cokolwiek zwrócą, będzie dostępna dla instancji usługi.

Przykład:

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

Funkcja usługi:

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

To jest inny sposób, możemy zarejestrować usługę. Jedyna różnica polega na sposobie, w jaki AngularJS próbuje utworzyć obiekt usługi. Tym razem kątowe używa słowa kluczowego "new" i wywołuje funkcję konstruktora podobną do poniższej.

var serviceInstance = new fnServiceConstructor();

W funkcji konstruktora możemy użyć słowa kluczowego "this" do dodania właściwości / metod do obiektu usługi. przykład:

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

Funkcja dostawcy:

Funkcja Provider () jest kolejną metodą tworzenia usług. Pozwól nam stworzyć usługę, która wyświetla użytkownikowi wiadomość powitalną. Ale chcemy również zapewnić taką funkcjonalność, aby użytkownik mógł ustawić własne powitanie. Z technicznego punktu widzenia chcemy tworzyć konfigurowalne usługi. Jak możemy to zrobić? Musi być jakiś sposób, aby aplikacja mogła przekazywać niestandardowe komunikaty powitalne, a Angularjs udostępniłby funkcję fabryka / konstruktora, która tworzy nasze instancje usług. W takim przypadku funkcja provider () wykonuje zadanie. za pomocą funkcji provider () możemy tworzyć konfigurowalne usługi.

Możemy tworzyć konfigurowalne usługi przy użyciu składni dostawcy, jak podano poniżej.

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

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

W jaki sposób działa składnia dostawcy?

1. Obiekt Provider tworzony jest przy użyciu funkcji konstruktora, którą zdefiniowaliśmy w naszej funkcji providera.

var serviceProvider = new serviceProviderConstructor();

2. Funkcja, którą przekazaliśmy w app.config (), zostaje wykonana. Nazywa się to fazą konfiguracji, a tutaj mamy szansę na dostosowanie naszej usługi.

configureService(serviceProvider);

3. Zasadniczo instancja usługi jest tworzona przez wywołanie metody $ get usługi ServiceProvider.

serviceInstance = serviceProvider.$get()

Przykładowy kod do tworzenia usługi za pomocą podaj składnię:

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

Robocza wersja demonstracyjna

Podsumowanie:


Fabryka użyj funkcji fabrycznej, która zwraca instancję usługi. serviceInstance = fnFactory ();

Usługa użyj funkcji konstruktora i Angular wywołaj tę funkcję konstruktora, używając słowa kluczowego "new" do utworzenia instancji usługi. serviceInstance = new fnServiceConstructor ();

Dostawca definiuje funkcję providerConstructor, ta funkcja providerConstructor definiuje funkcję fabryczną $ get . Połączenia kątowe $ get () w celu utworzenia obiektu usługi. Składnia dostawcy ma dodatkową zaletę polegającą na konfigurowaniu obiektu usługi, zanim zostanie on utworzony. serviceInstance = $ get ();


133
2017-11-19 13:36





Jak zauważyło kilka osób tutaj, fabryka, dostawca, usługa, a nawet wartość i stała są wersjami tego samego. Możesz przeanalizować bardziej ogólny provider do wszystkich. Tak jak w przypadku:

enter image description here

Oto artykuł, z którego pochodzi ten obraz:

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


79
2017-08-02 05:37





Fabryka

Dajesz AngularJS funkcję, AngularJS buforuje i wprowadza wartość zwracaną, gdy zażąda fabryki.

Przykład:

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

Stosowanie:

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

Usługa

Dajesz AngularJS funkcję, którą wywoła AngularJS Nowy aby utworzyć instancję. Jest to instancja tworzona przez AngularJS, która będzie buforowana i wstrzykiwana, gdy żądana jest usługa. Od Nowy został użyty do utworzenia instancji usługi, słowa kluczowego to jest poprawna i odnosi się do instancji.

Przykład:

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

Stosowanie:

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

Dostawca

Dajesz AngularJS funkcję, a AngularJS wywoła ją $get funkcjonować. Jest to wartość zwracana przez $get funkcja, która będzie buforowana i wstrzykiwana, gdy żądana jest usługa.

Dostawcy umożliwiają konfigurację dostawcy przed AngularJS dzwoni do $get metoda uzyskania wstrzykiwacza.

Przykład:

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

Użycie (jako wstrzykiwacz w kontrolerze)

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

Użycie (konfigurowanie dostawcy wcześniej $get jest wywoływany w celu utworzenia wstrzykiwacza)

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

62
2018-05-19 19:53





Podczas zabawy z dostawcami zauważyłem coś interesującego.

Widoczność preparatów do wstrzykiwania różni się w przypadku dostawców, niż w przypadku usług i fabryk. Jeśli zadeklarujesz stałą "AngularJS" (na przykład myApp.constant('a', 'Robert');), możesz wprowadzić go do usług, fabryk i dostawców.

Ale jeśli zadeklarujesz "wartość" AngularJS (np. myApp.value('b', {name: 'Jones'});), możesz wprowadzić go do usług i fabryk, ale NIE do funkcji tworzenia dostawcy. Możesz jednak wstrzyknąć go do $get funkcja zdefiniowana przez operatora. Jest to wspomniane w dokumentacji AngularJS, ale łatwo ją przeoczyć. Możesz go znaleźć na stronie% dostarczania w sekcjach dotyczących wartości i metod stałych.

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>

54
2017-10-09 03:43