AngularJS: Serviciu vs furnizor vs fabrică

Care sunt diferențele dintre un Service, Provider și Factory în AngularJS?

Soluția

De pe lista de discuții AngularJS am primit un fir de discuție uimitor care explică serviciul vs fabrica vs furnizorul și utilizarea injecției acestora. Compilarea răspunsurilor:

Servicii

Sintaxă: module.service( 'serviceName', function );`` <br/> Rezultatul: "Service": La declararea lui ServiceName ca argument injectabil **se va primi o instanță a funcției. Cu alte cuvinte**new FunctionYouPassedToService()`.

Factories

Sintaxă: `module.factory( 'factoryName', function );``
Rezultatul: Atunci când declarați factoryName ca argument injectabil, veți primi valoarea care este returnată prin invocarea referinței funcției transmise la module.factory.

Provideri

Sintaxă: module.provider( 'providerName', function );`` <br/> Rezultatul: "Provider": La declararea providerName ca argument injectabil **se va primi**(new ProviderFunction()).$get(). Funcția constructor este instanțiată înainte de apelarea metodei $get -ProviderFunction` este referința funcției transmisă la module.provider.

Furnizorii au avantajul că pot fi configurați în timpul fazei de configurare a modulului.

A se vedea aici pentru codul furnizat.

Aici'i o explicație suplimentară excelentă de către Misko:

provide.value('a', 123);

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

În acest caz, injectorul returnează pur și simplu valoarea așa cum este. Dar ce se întâmplă dacă doriți să calculați valoarea? Atunci folosiți o fabrică

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

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

Așadar, factory este o funcție care este responsabilă pentru crearea valorii. Observați că funcția factory poate solicita alte dependențe.

Dar ce se întâmplă dacă doriți să fiți mai OO și să aveți o clasă numită Greeter?

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

Atunci, pentru a o instanția, ar trebui să scrieți

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

Apoi am putea cere 'greeter' în controler astfel

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

Dar asta este mult prea mult prea mult. Un mod mai scurt de a scrie acest lucru ar fi `provider.service('greeter', Greeter);``.

Dar dacă am dori să configurăm clasa Greeter înainte de injecție? Atunci am putea scrie

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

Apoi putem face acest lucru:

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

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

Ca o notă suplimentară, service, factory și value sunt toate derivate din provider.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};
Comentarii (10)

[JS Fiddle Demo][1]

" Hello world " exemplu cu 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>

<div ng-controller="MyCtrl">
    {{hellos}}
</div>
Comentarii (7)

Am observat ceva interesant când m-am jucat cu furnizorii.

Vizibilitatea injectabilelor este diferită pentru furnizori față de cea pentru servicii și fabrici. Dacă declarați o "constantă" AngularJS (de exemplu, myApp.constant('a', 'Robert');), o puteți injecta în servicii, fabrici și furnizori.

Dar dacă declarați o "valoare" AngularJS (de exemplu, myApp.value('b', {name: 'Jones'});), o puteți injecta în servicii și fabrici, dar NU în funcția de creare a furnizorului. Cu toate acestea, o puteți injecta în funcția $get pe care o definiți pentru furnizorul dumneavoastră. Acest lucru este menționat în documentația AngularJS, dar este ușor de omis. O puteți găsi pe pagina %provide, în secțiunile referitoare la metodele value și 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>
Comentarii (0)