AngularJS : 서비스 대 공급자 대 팩토리


3319

는 A의 차이점은 무엇입니까 Service, ProviderFactoryAngularJS와에가?


244
나는 모든 Angular 용어가 초보자를 위협한다는 것을 알았습니다. 우리는 Angular demisx.github.io/angularjs/2014/09/14/… 를 배우면서 프로그래머가 이해하기 쉬운이 치트 시트로 시작했습니다 . 이것이 팀에도 도움이되기를 바랍니다.
demisx

7
내 의견으로는, 차이점을 이해하는 가장 좋은 방법은 Angular의 자체 문서를 사용하는 것입니다 . docs.angularjs.org/guide/providers 매우 잘 설명되어 있으며 이해를 돕기 위해 독특한 예를 사용합니다.
라파엘 멀린

3
@Blaise 감사합니다! 내 의견에 따르면 내 경험의 99 %가 사례를 통해 성공적으로 처리 될 수 있기 때문에 의도적으로 생략했습니다 service.factory. 이 주제를 더 복잡하게 만들고 싶지 않았습니다.
demisx

3
나는이 토론이 매우 유용하다는 것을 알았다 stackoverflow.com/questions/18939709/…
Anand Gupta

3
여기에 몇 가지 좋은 답변입니다 방법에 대한services,factories그리고providers작품.
Mistalis

답변:


2866

AngularJS 메일 링리스트에서 서비스 대 팩토리 대 공급자 및 주입 사용법을 설명 하는 놀라운 스레드 를 얻었습니다 . 답변을 컴파일 :

서비스

구문 : module.service( 'serviceName', function );
결과 : serviceName을 주입 가능한 인수로 선언 하면 함수의 인스턴스가 제공됩니다. 다시 말해 new FunctionYouPassedToService() .

공장

구문 : module.factory( 'factoryName', function );
결과 : factoryName을 주입 가능한 인수로 선언하면 module.factory에 전달 된 함수 참조를 호출하여 리턴되는 값이 제공됩니다 . .

공급자

구문 : module.provider( 'providerName', function );
결과 : providerName을 주입 가능한 인수로 선언 하면이 제공됩니다 (new ProviderFunction()).$get() . 생성자 함수는 $ get 메소드가 호출되기 전에 인스턴스화 ProviderFunction됩니다. 함수 참조는 module.provider에 전달됩니다.

공급자는 모듈 구성 단계에서 구성 할 수 있다는 이점이 있습니다.

제공된 코드는 여기 를 참조 하십시오 .

Misko의 훌륭한 추가 설명은 다음과 같습니다.

provide.value('a', 123);

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

이 경우 인젝터는 단순히 값을 그대로 반환합니다. 그러나 값을 계산하려면 어떻게해야합니까? 그런 다음 공장을 사용하십시오

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

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

그래서 factory가치 창출을 담당하는 기능도 입니다. 팩토리 기능은 다른 종속성을 요청할 수 있습니다.

그러나 더 많은 OO가되고 Greeter라는 클래스를 원한다면 어떻게해야합니까?

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

그런 다음 인스턴스화하려면 다음을 작성해야합니다.

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

그런 다음 컨트롤러에서 '인사'를 요청할 수 있습니다.

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

그러나 그것은 너무 장황합니다. 이것을 쓰는 더 짧은 방법은provider.service('greeter', Greeter);

그러나 Greeter주입 전에 클래스 를 구성하려면 어떻게해야 합니까? 그럼 우리는 쓸 수 있습니다

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

그런 다음이 작업을 수행 할 수 있습니다.

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

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

보조 노트로서 service, factory그리고 value모든 공급자에서 파생됩니다.

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

58
서비스와 공장의 차이점을 설명하는 stackoverflow.com/a/13763886/215945 도 참조하십시오 .
Mark Rajcok

3
편집 611에서 각도 상수와 값의 사용법을 추가했습니다. 상대방의 차이점을 이미 보여주기 위해. jsbin.com/ohamub/611/edit
Nick

17
함수의 인스턴스를 작성하여 서비스를 호출하지만. 실제로는 인젝터 당 한 번만 만들어 단일 톤처럼 만듭니다. docs.angularjs.org/guide/dev_guide.services.creating_services
angelokh

33
이 예제는 분명한 실제 예제를 사용하면 놀라 울 수 있습니다. 내가 좋아하는 것들의 어떤 점을 알아 내려고 노력 분실 toEqual하고 greeter.Greet있다. 좀 더 실제적이고 관련성이 높은 것을 사용하지 않겠습니까?
Kyle Pennell

5
expect () 함수를 사용하는 것은 무언가를 설명하기에 좋지 않은 선택입니다. 다음에 실제 코드를 사용하십시오.
Craig

812

JS 피들 데모

"안녕하세요 세계"예와 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>


2
함수의 this컨텍스트를 변경 하지 $get않습니까? -더 이상 해당 기능에서 인스턴스화 된 공급자를 참조하지 않습니다.
Nate-Wilkins

12
@Nate : this실제로 호출되는 것은 new Provider(). $ get () 이므로 컨텍스트가 변경되지 않습니다 . 여기서 Provider함수가 전달됩니다 app.provider. 즉, 그것이 $get()construct에 대한 메소드로 호출 Provider되므로 예제에서 제안 this하는 Provider대로 참조됩니다 .
Brandon

1
@Brandon Ohh 알았어 그거 참 깔끔한 데. 언뜻보기에 혼란 스럽습니다-설명 주셔서 감사합니다!
Nate-Wilkins

3
Unknown provider: helloWorldProvider <- helloWorld로컬로 실행할 때 왜 얻 습니까? 주석 처리하면 다른 두 예제와 동일한 오류가 발생합니다. 숨겨진 공급자 구성이 있습니까? (Angular 1.0.8)-발견 : stackoverflow.com/questions/12339272/…
앙투안

4
.config 코드에서 'helloWorldProvider'를 사용하지만 myApp.provider ( 'helloWorld', function ())에서 공급자를 정의 할 때 @Antoine에서 "Unknown provide : helloWorldProvider"오류가 발생하는 이유는 무엇입니까? 'helloWorld'? 즉, 구성 코드에서 angular는 helloWorld 공급자를 참조하고 있음을 어떻게 알 수 있습니까? 감사합니다
jmtoung

645

TL; DR

1) 당신이 사용하고있는 공장을 객체를 만든 다음 같은 개체를 반환, 그것에 속성을 추가 할 수 있습니다. 이 팩토리를 컨트롤러에 전달하면 이제 해당 컨트롤러에서 팩토리를 통해 객체의 해당 속성을 사용할 수 있습니다.

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) Service를 사용할 때 AngularJS는 'new'키워드를 사용하여 장면 뒤에서 인스턴스화합니다. 이 때문에 'this'에 속성을 추가하면 서비스는 'this'를 반환합니다. 서비스를 컨트롤러로 전달하면 이제 'this'에 대한 해당 속성을 서비스를 통해 해당 컨트롤러에서 사용할 수 있습니다.

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

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



3) 공급자 는 .config () 함수에 전달할 수있는 유일한 서비스입니다. 서비스 오브젝트를 사용하기 전에 모듈 전체 구성을 제공하려는 경우 제공자를 사용하십시오.

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



비 TL; DR

1) 팩토리
팩토리는 서비스를 생성하고 구성하는 가장 보편적 인 방법입니다. TL; DR이 말한 것보다 훨씬 많지는 않습니다. 객체를 생성하고 속성을 추가 한 다음 동일한 객체를 반환하면됩니다. 그런 다음 팩토리를 컨트롤러로 전달하면 이제 해당 컨트롤러의 팩토리를 통해 객체의 해당 속성을 사용할 수 있습니다. 보다 광범위한 예는 다음과 같습니다.

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

이제 'myFactory'를 컨트롤러에 전달하면 'service'에 첨부 한 모든 속성을 사용할 수 있습니다.

이제 콜백 함수에 '비공개'변수를 추가하겠습니다. 이것들은 컨트롤러에서 직접 액세스 할 수는 없지만 결국 'service'에서 getter / setter 메소드를 설정하여 필요할 때 이러한 'private'변수를 변경할 수 있습니다.

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

여기서는 변수 / 함수를 'service'에 첨부하지 않습니다. 나중에 사용하거나 수정하기 위해 단순히 만들었습니다.

  • baseUrl은 iTunes API에 필요한 기본 URL입니다
  • _artist는 조회하고자하는 아티스트입니다.
  • _finalUrl은 iTunes를 호출 할 최종 완성 된 URL입니다.
  • makeUrl은 iTunes 친화적 인 URL을 생성하고 반환하는 기능입니다.

헬퍼 / 프라이빗 변수와 함수가 준비되었으므로 'service'객체에 속성을 추가해 봅시다. 우리가 '서비스'에 넣은 것은 'myFactory'를 전달하는 컨트롤러 내에서 직접 사용할 수 있습니다.

아티스트를 반환하거나 설정하는 setArtist 및 getArtist 메소드를 작성하려고합니다. 또한 생성 된 URL을 사용하여 iTunes API를 호출하는 메소드를 작성하려고합니다. 이 방법은 일단 데이터가 iTunes API에서 돌아 오면 이행 할 것을 약속합니다. AngularJS에서 약속을 사용한 경험이 많지 않은 경우 약속을 자세히 살펴 보는 것이 좋습니다.

아래 setArtist 는 아티스트를 허용하며 아티스트를 설정할 수 있습니다. getArtist 는 아티스트를 반환합니다. callItunes 는 $ http 요청에 사용할 URL을 만들기 위해 makeUrl ()을 먼저 호출합니다. 그런 다음 promise 객체를 설정하고 최종 URL로 $ http 요청을 한 다음 $ http는 promise를 반환하므로 요청 후 .success 또는 .error를 호출 할 수 있습니다. 그런 다음 iTunes 데이터로 약속을 해결하거나 '오류가 발생했습니다'라는 메시지와 함께 거부합니다.

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

이제 우리 공장은 완성되었습니다. 이제 모든 컨트롤러에 'myFactory'를 주입 할 수 있으며 서비스 객체 (setArtist, getArtist 및 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);
      })
  }
});

위의 컨트롤러에서 우리는 'myFactory'서비스에 주입하고 있습니다. 그런 다음 'myFactory'의 데이터를 사용하여 $ scope 객체의 속성을 설정합니다. 위의 유일한 까다로운 코드는 이전에 약속을 다루지 않은 경우입니다. callItunes가 약속을 반환하므로 .then () 메서드를 사용하고 iTunes 데이터로 약속이 이행 된 후에 만 ​​$ scope.data.artistData를 설정할 수 있습니다. 컨트롤러가 매우 얇다는 것을 알 수 있습니다 (이것은 좋은 코딩 연습입니다). 모든 논리 및 영구 데이터는 컨트롤러가 아닌 서비스에 있습니다.

2) 서비스
아마도 서비스 생성을 처리 할 때 알아야 할 가장 큰 것은 '새로운'키워드로 인스턴스화된다는 것입니다. JavaScript 전문가에게는 이것이 코드의 특성에 대한 큰 힌트를 제공해야합니다. JavaScript에 대한 배경 지식이 제한적인 사용자 또는 'new'키워드의 실제 기능에 익숙하지 않은 사용자를 위해 서비스의 본질을 이해하는 데 도움이되는 JavaScript 기본 사항을 검토하겠습니다.

'new'키워드로 함수를 호출 할 때 발생하는 변경 사항을 실제로 보려면 함수를 작성하고 'new'키워드로 호출 한 다음 'new'키워드를 볼 때 인터프리터가 수행하는 작업을 보여 드리겠습니다. 최종 결과는 동일합니다.

먼저 생성자를 만들어 봅시다.

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

일반적인 JavaScript 생성자 함수입니다. 이제 'new'키워드를 사용하여 Person 함수를 호출 할 때마다 'this'는 새로 작성된 오브젝트에 바인드됩니다.

이제 Person의 프로토 타입에 메소드를 추가하여 Person '클래스'의 모든 인스턴스에서 사용할 수 있습니다.

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

이제 프로토 타입에 sayName 함수를 추가 했으므로 Person의 모든 인스턴스는 해당 인스턴스 이름을 알리기 위해 sayName 함수를 호출 할 수 있습니다.

이제 Person 생성자 함수와 프로토 타입에 sayName 함수가 있으므로 Person 인스턴스를 만든 다음 sayName 함수를 호출 해 보겠습니다.

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

따라서 Person 생성자를 생성하고 프로토 타입에 함수를 추가하고 Person 인스턴스를 생성 한 다음 프로토 타입에서 함수를 호출하는 코드는 다음과 같습니다.

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’

이제 JavaScript에서 'new'키워드를 사용할 때 실제로 어떤 일이 발생하는지 살펴 보겠습니다. 첫 번째로 주목해야 할 것은 예제에서 'new'를 사용한 후에는 마치 'tyler'에서 객체 인 것처럼 메소드 (sayName)를 호출 할 수 있다는 것입니다. 그 이유 때문입니다. 먼저, Person 생성자가 코드에서 볼 수 있는지 여부에 관계없이 Person 생성자가 객체를 반환한다는 것을 알고 있습니다. 둘째, sayName 함수는 Person 인스턴스가 아닌 프로토 타입에 있으므로 Person 함수가 반환하는 객체는 실패한 조회에서 프로토 타입에 위임되어야합니다. 더 간단한 용어로, tyler.sayName ()을 호출하면 인터프리터는“OK, 방금 만든 'tyler'객체를보고 sayName 함수를 찾은 다음 호출합니다. 잠깐만 요, 여기 보이지 않습니다-내가 볼 수있는 것은 이름과 나이, 프로토 타입을 확인하겠습니다. 예, 프로토 타입에있는 것 같습니다.”라고 말합니다.

아래는 JavaScript에서 'new'키워드가 실제로하는 일에 대해 어떻게 생각할 수 있는지에 대한 코드입니다. 기본적으로 위 단락의 코드 예입니다. 나는 '인터프리터 뷰'또는 인터프리터가 코드 내부의 코드를 보는 방식을 넣었습니다.

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

이제 'new'키워드가 JavaScript에서 실제로 수행하는 작업에 대한 지식이 있으면 AngularJS에서 서비스를 작성하는 것이 이해하기 쉬워야합니다.

서비스를 만들 때 이해해야 할 가장 큰 것은 서비스가 'new'키워드로 인스턴스화된다는 것입니다. 위의 예제와 그 지식을 결합하여 이제 속성과 메소드를 'this'에 직접 첨부하여 서비스 자체에서 반환한다는 것을 인식해야합니다. 이것을 실제로 살펴 봅시다.

우리가 팩토리 예제로 원래했던 것과는 달리, 우리는 객체를 생성 할 필요가 없습니다. 이전에 여러 번 언급했듯이 인터프리터가 해당 객체를 생성하고 위임 할 수 있도록 'new'키워드를 사용했기 때문입니다. 그것은 프로토 타입이고, 우리가 작업을하지 않아도 우리를 위해 그것을 돌려줍니다.

먼저, '비공개'및 도우미 기능을 만들어 봅시다. 우리가 공장과 똑같은 일을했기 때문에 이것은 매우 친숙하게 보일 것입니다. 팩토리 예제에서 각 라인이 무엇을하는지 설명하지 않겠습니다. 혼란 스러우면 팩토리 예제를 다시 읽으십시오.

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'에 첨부하겠습니다.

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

});

이제 팩토리 에서처럼 setArtist, getArtist 및 callItunes는 myService를 전달하는 컨트롤러에서 사용할 수 있습니다. 다음은 myService 컨트롤러입니다 (공장 컨트롤러와 거의 동일).

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

앞에서 언급했듯이 '새로운'기능을 실제로 이해하면 서비스는 AngularJS의 공장과 거의 동일합니다.

3) 공급자

제공자에 대해 기억해야 할 가장 큰 것은 제공자가 애플리케이션의 app.config 부분으로 전달할 수있는 유일한 서비스라는 것입니다. 애플리케이션의 다른 곳에서 사용하기 전에 서비스 오브젝트의 일부를 변경해야하는 경우 이는 매우 중요합니다. 서비스 / 공장과 매우 ​​유사하지만 몇 가지 차이점이 있습니다.

먼저 우리는 서비스 및 공장과 비슷한 방식으로 공급자를 설정했습니다. 아래 변수는 '비공개'및 도우미 기능입니다.

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

* 위 코드의 일부가 혼란 스러우면 팩토리 섹션에서 자세한 내용을 설명합니다.

제공자는 3 개의 섹션이 있다고 생각할 수 있습니다. 첫 번째 섹션은 나중에 수정 / 설정 될 '비공개'변수 / 함수입니다 (위 그림 참조). 두 번째 섹션은 app.config 함수에서 사용할 수있는 변수 / 함수이므로 다른 곳에서 사용 가능하기 전에 변경할 수 있습니다 (위에 표시됨). 이러한 변수는 'this'키워드에 첨부해야합니다. 이 예에서는 app.config에서 'thingFromConfig'만 변경할 수 있습니다. 세 번째 섹션 (아래 참조)은 'myProvider'서비스를 특정 컨트롤러로 전달할 때 컨트롤러에서 사용할 수있는 모든 변수 / 기능입니다.

Provider로 서비스를 생성 할 때 컨트롤러에서 사용할 수있는 유일한 속성 / 방법은 $ get () 함수에서 반환되는 속성 / 방법입니다. 아래 코드는 $ get을 'this'에 넣습니다. 이제 $ get 함수는 컨트롤러에서 사용할 수있는 모든 메소드 / 속성을 반환합니다. 다음은 코드 예입니다.

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

이제 전체 제공자 코드는 다음과 같습니다

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

이제 팩토리 및 서비스 에서처럼 setArtist, getArtist 및 callItunes는 myProvider를 전달하는 컨트롤러에서 사용할 수 있습니다. 다음은 myProvider 컨트롤러입니다 (공장 / 서비스 컨트롤러와 거의 동일).

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

앞에서 언급했듯이 Provider를 사용하여 서비스를 만드는 요점은 최종 객체가 나머지 응용 프로그램으로 전달되기 전에 app.config 함수를 통해 일부 변수를 변경할 수 있다는 것입니다. 그 예를 보자.

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

이제 제공자에서 'thingFromConfig'가 빈 문자열로 어떻게 표시되는지 확인할 수 있지만 DOM에 표시되면 '이 문장이 설정되었습니다…'가됩니다.


11
이 뛰어난 글쓰기에서 빠진 유일한 부분은 공장보다 서비스를 사용하는 상대적인 장점입니다. 이것은 Lior에 의해 수용된 답변에 명확하게 설명되어 있습니다
무한대

2
FWIW는 (아마 많은), 여기 각도로 문제를 소요 블로거이며, providerProvider 좋아하지 않는 codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
'자바 스크립트 전문가'펀치 라인은 교활했습니다. : DI는이 답변이 많은 것을 해결한다고 생각합니다. 훌륭하게 작성되었습니다.
amarmishra

4
TLDR에는 TLDR이 필요합니다.
JensB

3
@JensB tl; dr-반응 배우기.
Tyler McGinnis가

512

모든 서비스는 싱글 톤입니다 . 앱마다 한 번씩 인스턴스화됩니다. 프리미티브, 객체 리터럴, 함수 또는 사용자 정의 유형의 인스턴스이든 관계없이 모든 유형 이 될 수 있습니다 .

value, factory, service, constant, 및 provider방법은 모든 공급자입니다. 그들은 인젝터에게 서비스를 인스턴스화하는 방법을 가르칩니다.

가장 장황하지만 가장 포괄적 인 것은 제공자 레시피입니다. 나머지 4 개 조리법 유형 - 값, 공장, 서비스 및 상수는 - 공급자 조리법의 상단에 단지 문법 설탕 있습니다 .

  • 값 레시피는 당신이 서비스를 직접 인스턴스화하고 제공하는 간단한 경우이다 인스턴스화 값 인젝터에 있습니다.
  • 공장 조리법은 이 서비스의 인스턴스를 필요로 할 때 호출하는 인젝터를 공장 기능을 제공합니다. 호출되면 팩토리 함수 는 서비스 인스턴스를 작성하고 리턴합니다. 서비스의 종속성은 함수의 인수로 삽입됩니다. 이 레시피를 사용하면 다음과 같은 능력이 추가됩니다.
    • 다른 서비스를 사용할 수있는 기능 (종속성이 있음)
    • 서비스 초기화
    • 지연 / 지연 초기화
  • 서비스 조리법은 거의 공장 조리법과 동일하지만, 여기에 인젝터는 호출 생성자 new 연산자 대신 공장 기능을.
  • 제공자 조리법은 일반적으로 과잉 . 팩토리 작성을 구성 할 수 있도록하여 간접 계층을 하나 더 추가합니다.

    응용 프로그램을 시작하기 전에 작성해야하는 응용 프로그램 전체 구성에 대한 API를 노출하려는 경우에만 제공자 레시피를 사용해야합니다. 이것은 일반적으로 응용 프로그램마다 동작이 약간 다를 수있는 재사용 가능한 서비스에만 유용합니다.

  • 상수 조리법은 그냥 당신이에서 사용할 수있는 서비스를 정의 할 수 있습니다 제외하고는 값 조리법처럼 구성 단계. Value 레시피를 사용하여 생성 된 서비스보다 빨리. 값과 달리을 사용하여 꾸밀 수는 없습니다 decorator.
공급자 설명서를 참조하십시오 .


2
서비스와 공장은 본질적으로 동일합니까? 다른 것 중 하나를 사용하면 대체 구문 외에는 아무것도 제공되지 않습니까?
Matt

2
@Matt, 예, 서비스는 서비스로 노출하려는 고유 한 기능이 이미있을 때 간결한 방법입니다. 문서에서 : myApp.factory ( 'unicornLauncher', [ "apiToken", function (apiToken) {return new UnicornLauncher (apiToken);}]); vs : myApp.service ( 'unicornLauncher', [ "apiToken", UnicornLauncher]);
janek

5
@ joshperry 초보자로서 서비스와 팩토리의 차이점을 잠시 동안 봤습니다. 이것이 최고의 답변이라는 데 동의합니다! 서비스를 서비스 클래스 (예 : 인코더 / 디코더 클래스)로 이해하는데 개인 속성이있을 수 있습니다. 그리고 팩토리는 상태 비 저장 헬퍼 메소드 세트를 제공합니다.
stanleyxu2005

3
위의 다른 답변에서 Yaa 예제는 이러한 레시피가 인스턴스화 될 때 주입되는 서비스와 공급자의 핵심 차이점을 명확하게 설명하지 못합니다.
Ashish Singh

223

AngularJS 팩토리, 서비스 및 제공자 이해

이들 모두는 재사용 가능한 싱글 톤 객체를 공유하는 데 사용됩니다. 앱 / 다양한 구성 요소 / 모듈에서 재사용 가능한 코드를 공유하는 데 도움이됩니다.

Docs Service / Factory에서 :

  • 지연 인스턴스화 – Angular는 응용 프로그램 구성 요소가 의존하는 경우에만 서비스 / 공장을 인스턴스화합니다.
  • 싱글 톤 – 서비스에 종속 된 각 구성 요소는 서비스 팩토리에서 생성 된 단일 인스턴스에 대한 참조를 가져옵니다.

공장

팩토리는 객체를 만들기 전에 로직을 조작 / 추가 할 수있는 기능으로 새로 만든 객체가 반환됩니다.

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

용법

클래스와 같은 함수 모음 일 수 있습니다. 따라서 컨트롤러 / 공장 / 지시 기능 내부에 주입 할 때 다른 컨트롤러에서 인스턴스화 할 수 있습니다. 앱당 한 번만 인스턴스화됩니다.

서비스

서비스를 보면서 간단히 어레이 프로토 타입에 대해 생각하십시오. 서비스는 'new'키워드를 사용하여 새 객체를 인스턴스화하는 기능입니다. this키워드 를 사용하여 서비스 개체에 속성과 기능을 추가 할 수 있습니다 . 팩토리와 달리 아무것도 반환하지 않습니다 (메소드 / 속성을 포함하는 객체를 반환합니다).

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

용법

응용 프로그램 전체에서 단일 객체를 공유해야 할 때 사용하십시오. 예를 들어, 인증 된 사용자 정보, 공유 가능한 방법 / 데이터, 유틸리티 기능 등

공급자

공급자는 구성 가능한 서비스 개체를 만드는 데 사용됩니다. 구성 기능에서 서비스 설정을 구성 할 수 있습니다. $get()함수 를 사용하여 값을 반환 합니다. $get기능은 각도에서 실행 단계에서 실행됩니다.

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

용법

서비스 개체를 사용하기 전에 모듈 단위 구성을 제공해야하는 경우 (예 : 당신처럼 환경 기준에 API의 URL을 설정하려는 가정 dev, stage또는prod

노트

angular의 구성 단계에서는 공급자 만 사용할 수 있지만 서비스 및 팩토리는 제공되지 않습니다.

이것이 공장, 서비스 및 공급자에 대한 이해를 명확하게 해주길 바랍니다 .


1
특정 인터페이스로 서비스를 원하지만 두 가지 구현이 있고 각각 컨트롤러에 주입하지만 ui-router를 사용하여 다른 상태에 묶인 경우 어떻게해야합니까? 예를 들어 한 상태에서 원격 호출을 수행하지만 다른 상태에서는 로컬 저장소에 기록합니다. 공급자 문서가을 사용한다고 말 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했으므로 소리가 들리지 않습니까?
qix

191

저에게 계시는 그들이 모두 같은 방식으로 작동한다는 것을 깨달았을 때 나타났습니다. 무언가를 한 번 실행하고 얻은 값을 저장 한 다음 의존성 주입을 통해 참조 할 때 동일한 저장된 값 을 기침합니다 .

우리가 가지고 있다고합시다.

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

세 가지의 차이점은 다음과 같습니다.

  1. a저장된 값은 실행에서 비롯됩니다 fn.
  2. b저장된 가치는 newing 에서 나옵니다 fn.
  3. c'저장 s의 값은 첫번째로 인스턴스를 얻기에서 오는 new보내고 fn, 다음 실행중인 $get인스턴스의 방법을.

이것은 AngularJS 내부에 캐시 객체와 같은 것을 의미합니다. 각 주입 값은 처음 주입되었을 때 한 번만 할당되며 어디서 :

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

이것이 우리 this가 서비스에서 사용 this.$get하고 공급자를 정의하는 이유 입니다.


2
나는 또한이 답변을 가장 좋아합니다. 그들 모두의 요점은 DI를 통해 필요할 때마다 객체에 대한 액세스를 제공하는 것입니다. 일반적으로 factorys로 잘하고 있습니다. serviceCoffeeScript, TypeScript, ES6 등과 같은 언어가 존재 하는 유일한 이유 는 클래스 구문을 사용할 수 있다는 것입니다. provider를 사용하여 설정이 다른 여러 응용 프로그램에서 모듈을 사용하는 경우에만 이 옵션이 필요합니다 app.config(). 서비스가 순수한 싱글 톤이거나 무언가의 인스턴스를 만들 수있는 경우 구현에 따라 다릅니다.
Andreas Linnert

137

서비스 대 공급자 대 공장 :

간단하게 유지하려고합니다. 기본 JavaScript 개념에 관한 것입니다.

우선 AngularJS의 서비스 에 대해 이야기합시다 !

서비스 란? : AngularJS에서 서비스유용한 메소드 또는 속성을 저장할 수있는 싱글 톤 JavaScript 객체 일뿐입니다. 이 싱글 톤 객체는 ngApp (Angular app) 단위로 생성되며 현재 앱 내의 모든 컨트롤러간에 공유됩니다. Angularjs는 서비스 객체를 인스턴스화 할 때이 서비스 객체를 고유 한 서비스 이름으로 등록합니다. 따라서 서비스 인스턴스가 필요할 때마다 Angular는이 서비스 이름에 대한 레지스트리를 검색하고 서비스 객체에 대한 참조를 반환합니다. 서비스 객체에서 메소드를 호출하고 속성에 액세스 할 수 있도록합니다. 컨트롤러의 스코프 객체에 속성, 메소드를 넣을 수 있는지에 대한 의문이 생길 수 있습니다! 왜 서비스 객체가 필요합니까? 답은 여러 컨트롤러 범위에서 서비스를 공유한다는 것입니다. 컨트롤러의 범위 객체에 일부 속성 / 메소드를 넣으면 현재 범위에서만 사용할 수 있습니다.

따라서 컨트롤러 범위가 세 개인 경우 controllerA, controllerB 및 controllerC로 지정하면 모두 동일한 서비스 인스턴스를 공유하게됩니다.

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

서비스를 만드는 방법?

AngularJS는 서비스를 등록하는 다른 방법을 제공합니다. 여기서 우리는 세 가지 방법 factory (..), service (..), provider (..)에 집중할 것입니다.

코드 참조를 위해이 링크를 사용하십시오

공장 기능 :

아래와 같이 팩토리 함수를 정의 할 수 있습니다.

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

AngularJS는 serviceName과 JavaScript 함수라는 두 개의 매개 변수를 사용하는 'factory ('serviceName ', fnFactory)' 메서드를 제공합니다. Angular 는 아래와 같이 fnFactory () 함수를 호출하여 서비스 인스턴스를 만듭니다 .

var serviceInstace = fnFactory();

전달 된 함수는 객체를 정의하고 해당 객체를 반환 할 수 있습니다. AngularJS는 단순히이 객체 참조를 첫 번째 인수로 전달되는 변수에 저장합니다. fnFactory에서 반환 된 것은 serviceInstance에 바인딩됩니다. object를 반환하는 대신 함수, 값 등을 반환 할 수도 있습니다. 반환 할 내용은 서비스 인스턴스에서 사용할 수 있습니다.

예:

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('serviceName',function fnServiceConstructor(){})

다른 방법으로 서비스를 등록 할 수 있습니다. 유일한 차이점은 AngularJS가 서비스 객체를 인스턴스화하는 방식입니다. 이번에는 angular는 'new'키워드를 사용하고 아래와 같이 생성자 함수를 호출합니다.

var serviceInstance = new fnServiceConstructor();

생성자 함수에서 서비스 객체에 속성 / 메소드를 추가하기 위해 'this'키워드를 사용할 수 있습니다. 예:

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

공급자 기능 :

Provider () 함수는 서비스를 만드는 또 다른 방법입니다. 사용자에게 인사말 메시지 만 표시하는 서비스를 만들려고합니다. 그러나 사용자가 자신의 인사말 메시지를 설정할 수있는 기능도 제공하려고합니다. 기술적 인 관점에서 우리는 구성 가능한 서비스를 만들고 싶습니다. 우리는 어떻게 이것을 할 수 있습니까? 앱이 사용자 지정 인사말 메시지를 전달할 수 있고 Angularjs가 서비스 인스턴스를 만드는 팩토리 / 생성자 기능에서 사용할 수 있도록하는 방법이 있어야합니다. 이러한 경우 provider () 함수가 작업을 수행하십시오. provider () 함수를 사용하여 구성 가능한 서비스를 만들 수 있습니다.

아래와 같이 공급자 구문을 사용하여 구성 가능한 서비스를 만들 수 있습니다.

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

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

공급자 구문은 내부적으로 어떻게 작동합니까?

1. 제공자 객체는 제공자 함수에서 정의한 생성자 함수를 사용하여 생성됩니다.

var serviceProvider = new serviceProviderConstructor();

2.app.config ()에 전달한 함수가 실행됩니다. 이를 구성 단계라고하며 여기에서 서비스를 사용자 정의 할 수 있습니다.

configureService(serviceProvider);

3. 마지막으로 serviceProvider의 $ get 메소드를 호출하여 서비스 인스턴스를 만듭니다.

serviceInstance = serviceProvider.$get()

제공 구문을 사용하여 서비스를 작성하기위한 샘플 코드 :

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

실무 데모

요약:


팩토리 는 서비스 인스턴스를 반환하는 팩토리 함수를 사용합니다. serviceInstance = fnFactory ();

서비스 는 생성자 함수를 사용하며 Angular는 서비스 인스턴스 작성을 위해 'new'키워드를 사용하여이 생성자 함수를 호출합니다. serviceInstance = 새 fnServiceConstructor ();

공급자 는 providerConstructor 함수를 정의하고이 providerConstructor 함수는 팩토리 함수 $ get을 정의합니다 . Angular는 $ get ()을 호출하여 서비스 객체를 만듭니다. 공급자 구문에는 서비스 개체를 인스턴스화하기 전에 구성 할 수있는 이점이 있습니다. serviceInstance = $ get ();



63

공장

AngularJS에 함수를 제공하면 AngularJS는 팩토리가 요청 될 때 리턴 값을 캐시하고 삽입합니다.

예:

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

용법:

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

서비스

AngularJS에 함수를 제공하면 AngularJS는 new 를 호출 하여 인스턴스화합니다. AngularJS가 작성하는 인스턴스는 서비스가 요청 될 때 캐시되고 주입됩니다. 때문에 새로운 서비스를 인스턴스화하는 데 사용 된 키워드 유효하며, 인스턴스를 나타냅니다.

예:

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

용법:

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

공급자

AngularJS에 함수를 제공하면 AngularJS가 해당 $get함수 를 호출 합니다. 에서 반환 값입니다$get서비스 요청시 캐시되고 주입 될 함수 .

제공자를 사용하면 AngularJS가 메소드를 호출 하기 전에 제공자를 구성 $get하여 인젝터 블을 얻을 수 있습니다.

예:

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

사용법 (컨트롤러에 주 사용으로)

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

사용법 ( $get주입기를 만들기 위해 공급자를 구성하기 전에 호출)

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

56

프로 바이더와 놀아 볼 때 뭔가 흥미로운 것을 발견했습니다.

주사제의 가시성은 서비스 및 공장과는 공급자가 다릅니다. AngularJS를 "constant"로 선언하면 (예 :myApp.constant('a', 'Robert'); 서비스, ​​팩토리 및 제공자에이를 삽입 할 수 있습니다.

그러나 AngularJS "값"(예 :)을 선언하면 myApp.value('b', {name: 'Jones'});서비스 및 팩토리에 삽입 할 수 있지만 제공자 작성 함수에는 삽입 할 수 없습니다. 그러나 $get제공자에 대해 정의한 함수에 이를 삽입 할 수 있습니다. 이것은 AngularJS 문서에 언급되어 있지만 놓치기 쉽습니다. % provide 페이지의 value 및 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>

45

이것은 초보자에게는 매우 혼란스러운 부분이며 쉬운 말로 명확하게하려고했습니다.

AngularJS 서비스 : 컨트롤러의 서비스 참조와 유틸리티 기능을 공유하는 데 사용됩니다. 서비스는 본질적으로 싱글 톤이므로 하나의 서비스에 대해 하나의 인스턴스 만 브라우저에 작성되며 페이지 전체에서 동일한 참조가 사용됩니다.

서비스 에서이 객체를 사용하여 함수 이름을 속성으로 만듭니다.

AngularJS Factory : Factory 의 목적은 Service와 동일하지만이 경우 새 객체를 만들고 함수를이 객체의 속성으로 추가하고 결국이 객체를 반환합니다.

AngularJS 제공자 : 이것 의 목적은 다시 동일하지만 제공자는 $ get 함수의 출력을 제공합니다.

Service, Factory 및 Provider 정의 및 사용은 http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider에 설명되어 있습니다 .


2
공장과 공급자도 싱글 톤 객체입니까? 공장이 서비스보다 권장되는 모든 scanrio?
Sunil Garg

34

나에게 차이점을 이해하는 가장 좋고 간단한 방법은 다음과 같습니다.

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

AngularJS가 특정 컴포넌트를 인스턴스화하는 방법 (단순화) :

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

// factory
var angularFactory = factory(injection);

따라서 서비스의 경우 AngularJS 구성 요소가되는 것은 서비스 선언 함수로 표시되는 클래스의 객체 인스턴스입니다. 팩토리의 경우 팩토리 선언 함수에서 리턴 된 결과입니다. 공장은 서비스와 동일하게 작동 할 수 있습니다.

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

가장 간단한 사고 방식은 다음과 같습니다.

  • 서비스는 싱글 톤 객체 인스턴스입니다. 코드에 싱글 톤 객체를 제공하려면 서비스를 사용하십시오.
  • 공장은 수업입니다. 코드에 사용자 정의 클래스를 제공하려는 경우 팩토리를 사용하십시오 (이미 인스턴스화되어 있으므로 서비스로 수행 할 수 없음).

팩토리 '클래스'예제는 주석과 공급자 차이에 대한 주석으로 제공됩니다.


서비스가 사용될 때마다 인스턴스화되면 어떻게 단일 서비스가 될 수 있습니까? 나는 그 주위에 내 머리를 얻을 수 있습니다 ...
joe

의존성 해결 중에는 서비스가 한 번만 인스턴스화되고 인젝터에서 서비스를 요청하면 항상 동일한 인스턴스를 얻게됩니다. jsfiddle.net/l0co/sovtu55t/1 에서 쉽게 확인할 수 있습니다 . 콘솔로 실행하십시오. 콘솔은 서비스가 한 번만 인스턴스화되었음을 보여줍니다.
Lukasz Frankowski

오 알 겠어요 나는 문자 그대로 new MyService()또는 무언가 할 수있을 것으로 기대했다 :)
joe

33

이 문제에 대한 나의 설명 :

기본적으로 언급 된 모든 유형 (서비스, 공장, 공급자 등)은 구식 글로벌 변수와 마찬가지로 전역 변수 (물론 전체 응용 프로그램에 전역 변수)를 만들고 구성하는 것입니다.

전역 변수는 권장되지 않지만 이러한 전역 변수의 실제 사용법은 변수를 관련 컨트롤러에 전달하여 종속성 주입 을 제공 하는 것입니다.

"전역 변수"에 대한 값을 작성하는 데 많은 수준의 복잡성이 있습니다.

  1. 상수
    이것은 다른 언어의 상수 (JavaScript가없는 것)처럼 전체 응용 프로그램 동안 수정해서는 안되는 실제 상수를 정의합니다.

  2. 이것은 수정 가능한 값 또는 객체이며 다른 서비스 또는 팩토리를 생성 할 때 주입 될 수있는 일부 전역 변수의 역할을합니다 (자세한 내용 참조). 그러나 " 리터럴 값 " 이어야합니다. 즉, 실제 값을 써야하며 계산 또는 프로그래밍 논리를 사용할 수 없습니다 (즉, 39 또는 myText 또는 {prop : "value"} 는 괜찮습니다). 2 +2 는 아닙니다).
  3. 팩토리
    보다 일반적인 값으로 바로 계산할 수 있습니다. 값을 계산하는 데 필요한 논리를 사용하여 AngularJS에 함수를 전달하여 작동하며 AngularJS가이를 실행하고 이름이 지정된 변수에 반환 값을 저장합니다.
    객체 (이 경우 서비스 와 유사하게 기능 함 ) 또는 함수 (변수를 콜백 함수로 저장함) 를 반환 할 수 있습니다.
  4. 서비스
    서비스는 값이 객체 일 때만 유효한 더 박탈 된 팩토리 버전 으로, 생성자 인 것처럼 함수에 직접 로직을 작성하고 선언 및 액세스 할 수 있습니다. this 키워드를 사용하는 객체 속성
  5. 프로 바이더
    단순화 된 팩토리 버전 인 서비스와 달리 , 프로 바이더는 "글로벌"변수를 초기화하는보다 복잡하지만 더 유연한 방법이며, 가장 큰 유연성은 app.config에서 값을 설정하는 옵션입니다. 키워드를 사용하여 선언 된 속성이있는 함수를 공급자에게 전달하여 serviceprovider
    조합을 사용하는 것처럼 작동 합니다 . 그런 다음 파일을 통해 위의 속성을 설정 한 후 AngularJS가 실행 하는 별도의 $ .get 함수 와이 $ .get이 필요합니다.app.config
    app.config 함수는 팩토리 처럼 작동합니다. 위의 반환 값은 "전역"변수를 초기화하는 데 사용됩니다.

26

내 이해는 아래에서 매우 간단합니다.

팩토리 : 팩토리 내부에 객체를 만들어 반환하면됩니다.

서비스:

이 키워드를 사용하여 함수를 정의하는 표준 함수 만 있습니다.

공급자:

거기이다 $get당신이 정의하는 것이 목적은 데이터를 반환하는 객체를 얻을 수 있습니다.


당신은 공장과 서비스를 섞지 않았습니까? 서비스는 공장 반품 장소를 만듭니다.
Flavien Volken

서비스 이름을 주사 가능한 인수로 선언하면 함수의 인스턴스가 제공됩니다. 다시 말해 new FunctionYouPassedToService ()입니다. 이 객체 인스턴스는 AngularJS가 필요한 경우 나중에 다른 서비스 / 컨트롤러에 등록하고 주입하는 서비스 객체가됩니다. // factory factoryname을 주입 가능한 인수로 선언하면 module.factory에 전달 된 함수 참조를 호출하여 리턴되는 값이 제공됩니다.
사잔

좋아, 그래서… 각도에서 공장은 "서비스"가 실제로 공장 (일반적인 디자인 패턴 용어) 인 싱글 톤입니다 .
Flavien Volken

25

Angular 문서의 요약 :

  • 객체 생성 방법을 정의하는 5 가지 레시피 유형이 있습니다 : Value , Factory , Service , ProviderConstant .
  • 공장서비스 는 가장 일반적으로 사용되는 레시피입니다. 그들 사이의 유일한 차이점은 서비스 레시피가 사용자 정의 유형의 객체에 더 효과적이며 공장은 는 JavaScript 기본 요소 및 함수를 생성 할 수 있다는 것입니다.
  • 제공자 조리법의 핵심 조리법 유형이며, 다른 모든 것들 그것에 단지 문법 설탕 있습니다.
  • 공급자 는 가장 복잡한 레시피 유형입니다. 전역 구성이 필요한 재사용 가능한 코드를 작성하지 않는 한 필요하지 않습니다.

여기에 이미지 설명을 입력하십시오


SO의 베스트 답변 :

https://stackoverflow.com/a/26924234/165673 (<-GOOD) https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673


20

모든 좋은 답변은 이미 있습니다. ServiceFactory 에 몇 가지 포인트를 더 추가하고 싶습니다 . 서비스 / 공장의 차이점과 함께. 또한 다음과 같은 질문이있을 수 있습니다.

  1. 서비스 또는 공장을 사용해야합니까? 차이점이 뭐야?
  2. 그들은 같은 행동을합니까?

서비스와 팩토리의 차이점부터 시작하겠습니다.

  1. 둘 다 싱글 톤입니다 : Angular가 이것을 종속성으로 처음 찾을 때마다 서비스 / 팩토리의 단일 인스턴스를 만듭니다. 인스턴스가 생성되면 동일한 인스턴스가 영원히 사용됩니다.

  2. 동작이있는 객체를 모델링하는 데 사용할 수 있습니다 . 메소드, 내부 상태 변수 등을 모두 가질 수 있습니다. 그 코드를 작성하는 방법은 다를 수 있습니다.

서비스:

서비스는 생성자 함수이며 Angular는 new를 호출하여 인스턴스화합니다 yourServiceName(). 이것은 몇 가지를 의미합니다.

  1. 함수와 인스턴스 변수는 this .
  2. 값을 반환하지 않아도됩니다. Angular가 new yourServiceName()를 호출하면 this모든 속성을 가진 객체를 받습니다 .

샘플 예 :

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

Angular가이 MyService서비스를 의존하는 컨트롤러 에이 서비스를 주입하면 해당 컨트롤러는 MyServiceMyService.aServiceMethod ()와 같은 함수를 호출 할 수있는 기능을 갖게됩니다.

조심해 this :

생성 된 서비스는 객체이므로 그 안에있는 메소드는 호출 될 때이를 참조 할 수 있습니다.

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

ScoreKeeper.setScore예를 들어 서버에서 점수를 획득하여 점수를 초기화 한 경우와 같은 약속 체인 을 호출하려고 할 수 있습니다 . $http.get('/score').then(ScoreKeeper.setScore).이 문제는 바운드로 ScoreKeeper.setScore호출되어 오류가 발생합니다. 더 좋은 방법은입니다 . 서비스 메소드에서이를 사용하든 아니든 관계없이 호출 방법에주의하십시오.thisnull$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))

A로부터 값을 반환Service :

JavaScript 생성자가 작동하는 방식으로 인해 함수 (i.e., an Object)에서 복잡한 값을 반환 constructor하면 호출자가이 인스턴스 대신 해당 Object를 가져옵니다.

이것은 기본적으로 아래에서 팩토리 예제를 복사하여 붙여 넣을 수 있으며로 대체 factory하면 service작동합니다.

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

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

따라서 Angular가 새로운 MyService ()를 사용하여 서비스를 구성하면 MyService 인스턴스 대신 해당 api 객체를 얻습니다.

이것은 복잡한 값 (객체, 함수)에 대한 동작이지만 기본 유형에는 적용되지 않습니다.

공장 :

팩토리는 값을 반환하는 평범한 오래된 함수입니다. 반환 값은 팩토리에 의존하는 것에 주입되는 것입니다. Angular의 일반적인 팩토리 패턴은 다음과 같이 함수로 속성을 가진 객체를 반환하는 것입니다.

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

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

  return api;
});

팩토리 의존성에 대한 주입 된 값은 팩토리의 반환 값이며 객체 일 필요는 없습니다. 그것은 기능이 될 수 있습니다

위의 1 및 2 질문에 대한 답변 :

대부분의 경우 모든 것을 위해 팩토리를 사용하십시오. 그들의 행동은 이해하기 쉽습니다. 값을 반환할지 여부를 선택할 수 없으며 잘못된 일을한다면 버그가 발생하지 않습니다.

하지만 의존성으로 주입하는 것에 대해서는 여전히 "서비스"라고합니다.

서비스 / 공장 동작은 매우 유사하며 어떤 사람들은 둘 중 어느 쪽이든 괜찮다고 말할 것입니다. 다소 사실이지만 John Papa의 스타일 가이드의 조언을 따르고 공장을 고수하는 것이 더 쉽다는 것을 알았습니다. **


16

추가 설명은 팩토리는 기능 / 프리미티브를 작성할 수 있지만 서비스는 불가능하다는 것입니다. Epokk를 기반으로 한이 jsFiddle을 확인하십시오 : http://jsfiddle.net/skeller88/PxdSP/1351/ .

팩토리는 호출 할 수있는 함수를 반환합니다.

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

팩토리는 호출 할 수있는 메소드를 사용하여 오브젝트를 리턴 할 수도 있습니다.

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

서비스는 호출 할 수있는 메소드가있는 오브젝트를 리턴합니다.

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

자세한 내용은 차이점에 대해 쓴 게시물을 참조하십시오. http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


16

이미 좋은 답변이 있지만이 답변을 공유하고 싶습니다.

우선 : 제공자service$ injector (AngulaJS가 IoC 패턴을 처리하는 방식)에 의해 주입 될 것으로 가정 하는 (단일 오브젝트) 를 작성하는 방법 / 레시피 입니다.

그리고 Value, Factory, Service 및 Constant (4 가지 방법) – 공급자 방식 / 수령에 대한 구문 설탕 .

거기에 Service vs Factory일부가 덮여있다 : https://www.youtube.com/watch?v=BLzNCkPn3ao

서비스new실제로 키워드 에 관한 것입니다.

  1. 새로운 물건을 만듭니다
  2. 그것을 prototype객체에 연결
  3. 커넥트 contextthis
  4. 그리고 반환 this

그리고 팩토리 는 팩토리 패턴에 관한 것입니다. 해당 서비스와 같은 객체를 반환하는 함수가 포함되어 있습니다.

  1. 다른 서비스를 사용할 수있는 능력
  2. 서비스 초기화
  3. 지연 / 지연 초기화

그리고이 간단한 / 짧은 비디오 : 제공 업체 : https://www.youtube.com/watch?v=HvTZbQ_hUZY (공장에서 공급 업체로 어떻게 이동하는지 볼 수 있습니다)

공급자 레시피는 앱이 완전히 시작 / 초기화되기 전에 대부분 앱 구성에서 사용됩니다.


14

이 모든 게시물을 읽은 후에는 더 혼란 스럽습니다 .. 그러나 여전히 모든 것이 가치있는 정보입니다 .. 마지막으로 간단한 비교로 정보를 제공하는 다음 표를 찾았습니다.

  • 인젝터는 레시피를 사용하여 서비스 및 특수 목적 오브젝트의 두 가지 유형의 오브젝트를 작성합니다.
  • 객체 생성 방법을 정의하는 5 가지 레시피 유형이 있습니다 : Value, Factory, Service, Provider 및 Constant.
  • 공장과 서비스는 가장 일반적으로 사용되는 레시피입니다. 이들 간의 유일한 차이점은 서비스 레시피가 사용자 정의 유형의 객체에 더 효과적이며 팩토리는 JavaScript 기본 요소 및 함수를 생성 할 수 있다는 것입니다.
  • 공급자 레시피는 핵심 레시피 유형이며 다른 모든 유형은 구문 설탕입니다.
  • 공급자는 가장 복잡한 레시피 유형입니다. 전역 구성이 필요한 재사용 가능한 코드를 작성하지 않는 한 필요하지 않습니다.
  • 컨트롤러를 제외한 모든 특수 목적 객체는 공장 레시피를 통해 정의됩니다.

여기에 이미지 설명을 입력하십시오

초보자에게는 다음과 같이 이해하십시오 .- 이것은 유스 케이스를 정정하지 않을 수도 있지만 높은 수준에서는이 세 가지 유스 케이스입니다.

  1. 각도 모듈에서 사용하려면 구성 기능을 공급자로 만들어야합니다.

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

  1. Ajax 통화 또는 타사 통합 서비스가 필요합니다 .
  2. 데이터 조작을 위해 공장으로 생성

기본 시나리오의 경우 factory & Service가 동일하게 작동합니다.


13

다음은 AngularjS에서 객체 팩토리의 코드 템플릿으로 제시 한 브로일러 플레이트 코드입니다. 설명하기 위해 Car / CarFactory를 예로 사용했습니다. 컨트롤러에서 간단한 구현 코드를 만듭니다.

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

다음은 더 간단한 예입니다. 위도 및 경도를 노출하지만 다른 객체 속성을 통해 "위치"객체를 기대하는 타사 라이브러리를 사용하고 있습니다. 공급 업체 코드를 해킹하고 싶지 않아서 전달중인 "Position"개체를 조정했습니다.

    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

;


12

이 페이지와 문서 (마지막으로 본 이후 크게 향상 된 것 같습니다)를 참조로 사용하여 5 가지 종류의 공급자 중 4 가지를 사용하는 다음과 같은 실제 (-ish) 세계 데모를 작성했습니다. 가치, 상수, 공장 및 완전 공급 업체.

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>

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

작업 데모 .


12

이 답변은 주제 / 질문을 다룹니다

어떻게 Factory, Service 및 Constant — 공급자 레시피 위에 구문 설탕입니까?

또는

공장, 서비스 및 공급자가 내부적으로 어떻게 simailar인가

기본적으로 일어나는 일은

당신이 할 때 factory()당신이 세트 function업체의에 두 번째 인수로 제공 $get하고 (반환 provider(name, {$get:factoryFn })) 당신이 얻을 모두는 provider하지만, 이외의 특성 / 방법이없는$getprovider(이 구성 할 수 없습니다 수단)

공장의 소스 코드

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

service()그것을 만들 때 (서비스에서 제공 한 생성자의 인스턴스를 반환) function을 주입 하는 factory () constructor를 제공하여 반환합니다.

서비스 소스 코드

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

따라서 기본적으로 두 경우 모두 공급자가 제공 한 기능으로 $ get set을 얻지 만 구성 블록에 대해 provider ()에서 원래 제공 할 수있는 $ get 이외의 것을 제공 할 수 있습니다


11

나는 훌륭한 대답을 많이 알고 있지만 내가 사용하는 내 경험 공유해야
1. service기본의 대부분의 경우
2. factory특정 인스턴스가 서비스를 만드는 데 사용을

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

그리고 사용 :

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

10

파티에 늦었 어 그러나 나는 이것이 공장, 서비스 및 공급자 방법론을 사용하여 Angular JS Custom Services를 개발하고 배우거나 명확하게하고 싶은 사람에게 더 도움이된다고 생각했습니다.

AngularJS 사용자 정의 서비스를 개발하기위한 팩토리, 서비스 및 제공자 방법에 대해 명확하게 설명하는이 비디오를 보았습니다.

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

소스 코드 : http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

여기에 게시 된 코드는 독자에게 도움이되도록 위의 소스에서 직접 복사됩니다.

"공장"기반 사용자 정의 서비스의 코드는 다음과 같습니다 (http 서비스 호출과 함께 동기화 및 비동기 버전 모두와 함께 제공됨).

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

커스텀 서비스를위한 "서비스"방법론 코드 (이것은 '공장'과 매우 유사하지만 구문 관점과는 다릅니다) :

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

}]);

사용자 지정 서비스에 대한 "제공자"방법론 코드 (구성 할 수있는 서비스를 개발하려는 경우 필요) :

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

마지막으로 위의 서비스 중 하나에서 작동하는 UI :

<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

간단히 설명하기 위해 AngularJS 소스에서 서비스가 팩토리 함수를 호출하고 제공자 함수를 호출하는 것을 볼 수 있습니다.

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

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

9

간단한 방법으로 AngularJS에서 비즈니스 로직을 처리하는 세 가지 방법을 논의 해 봅시다 : ( Yaakov의 Coursera AngularJS 과정에서 영감을 얻음 )

서비스 :

통사론:

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>

서비스 특징 :

  1. 지연 인스턴스화 : 주입되지 않으면 인스턴스화되지 않습니다. 따라서 그것을 사용하려면 그것을 모듈에 주입해야합니다.
  2. 싱글 톤 : 여러 모듈에 주입 된 경우 모두 하나의 특정 인스턴스에만 액세스 할 수 있습니다. 여러 컨트롤러간에 데이터를 공유하는 것이 매우 편리한 이유입니다.

공장

먼저 문법을 보자 :

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

이제 컨트롤러에서 위의 두 가지를 사용하십시오.

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

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

공장 특징 :

  1. 공장 설계 패턴을 따릅니다. 공장은 새로운 물건이나 기능을 생산하는 중심 장소입니다.
  2. 싱글 톤뿐만 아니라 맞춤형 서비스도 제공합니다.
  3. .service()방법은 단일 유형 인 동일한 유형의 서비스를 항상 생성 하는 팩토리 이며 동작을 구성하기 쉬운 방법이 없습니다. 이 .service()방법은 일반적으로 구성이 필요없는 항목의 바로 가기로 사용됩니다.

공급자

구문을 먼저 다시 살펴 보겠습니다.

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

}

공급자의 특징 :

  1. 공급자는 Angular에서 가장 유연한 서비스 생성 방법입니다.
  2. 동적으로 구성 할 수있는 팩토리를 만들 수있을뿐만 아니라 팩토리를 사용할 때 제공자 메소드를 사용하여 전체 애플리케이션의 부트 스트랩에서 팩토리를 한 번만 사용자 정의 할 수 있습니다.
  3. 그런 다음 사용자 정의 설정으로 응용 프로그램 전체에서 팩토리를 사용할 수 있습니다. 다시 말해, 응용 프로그램이 시작되기 전에이 팩토리를 구성 할 수 있습니다. 실제로 앵귤러 문서에서 제공자 메소드는 서비스를 하나 .service또는 .factory메소드로 구성 할 때 실제로 뒤에서 실행되는 것 입니다.
  4. $get직접 공급자 인스턴스에 부착되는 함수이다. 그 기능은 공장 기능입니다. 다시 말해, 우리 가 메소드 에 제공 하는 것과 같습니다 .factory. 이 기능에서 우리는 우리 자신의 서비스를 만듭니다. $get함수 인 속성은 공급자를 공급자로 만드는 것 입니다. AngularJS는 프로 바이더가 Angular가 팩토리 함수로 취급 할 함수 인 $ get 속성을 가질 것으로 기대합니다. 그러나이 전체 제공자 설정을 매우 특별하게 만드는 것은 config서비스 제공자 내부에 일부 오브젝트를 제공 할 수 있다는 사실 이며, 일반적으로 전체 애플리케이션을 구성 할 수있는 단계에서 나중에 겹쳐 쓸 수있는 기본값이 제공됩니다.

7

팩토리 : 팩토리 내부에 실제로 객체를 생성하여 반환 한 팩토리입니다.
service : this 키워드를 사용하여 함수를 정의하는 표준 함수가있는 서비스입니다.
provider : 정의한 $ get가있는 제공자이며 데이터를 리턴하는 오브젝트를 얻는 데 사용할 수 있습니다.


7

기본적으로 공급자, 공장 및 서비스는 모두 서비스입니다. 팩토리는 $ get () 함수 만 있으면 더 적은 코드로 작성할 수있는 서비스의 특별한 경우입니다.

서비스, ​​공장 및 공급자 간의 주요 차이점은 복잡성입니다. 서비스는 가장 간단한 형태이며 공장은 좀 더 강력하며 공급자는 런타임에 구성 할 수 있습니다.

다음은 각각 사용시기에 대한 요약입니다.

공장 : 제공하는 값은 다른 데이터를 기반으로 계산해야합니다.

서비스 : 메소드가있는 객체를 반환합니다.

공급자 : 구성 단계에서 생성 될 개체를 생성하기 전에 구성 할 수 있습니다. 앱이 완전히 초기화되기 전에 대부분 앱 구성에서 제공자를 사용하십시오.


음. Value, Factory, Service 및 Constant는 공급자 레시피 위에 구문 설탕 일뿐입니다. Angularjs 문서-제공자
Sudarshan_SMD

네 동의합니다. 이제 각도 4로 더 이상 두통이 없습니다
eGhoul

4

1. 서비스는 필요할 때 만들어지고 응용 프로그램 수명주기가 끝날 때까지 (브라우저가 닫힐 때까지) 정리되지 않는 단일 개체입니다. 컨트롤러가 더 이상 필요하지 않으면 폐기 및 정리됩니다.

2. 서비스를 생성하는 가장 쉬운 방법은 factory () 메소드를 사용하는 것입니다. factory () 메소드를 사용하면 서비스 기능 및 서비스 데이터가 포함 된 객체를 반환하여 서비스를 정의 할 수 있습니다. 서비스 정의 기능은 $ http 및 $ q와 같이 주사 가능한 서비스를 배치하는 곳입니다. 전의:

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

앱에서 factory () 사용하기

런타임에 필요한 곳에 간단히 주입 할 수 있으므로 응용 프로그램에서 팩토리를 사용하는 것이 쉽습니다.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. 반면에 service () 메소드를 사용하면 생성자 함수를 정의하여 서비스를 작성할 수 있습니다. 원시 자바 스크립트 객체 대신 프로토 타입 객체를 사용하여 서비스를 정의 할 수 있습니다. factory () 메소드와 유사하게 함수 정의에서 인젝터 블도 설정합니다.
  2. 서비스를 작성하는 가장 낮은 레벨의 방법은 provide () 메소드를 사용하는 것입니다. 이것이 .config () 함수를 사용하여 구성 할 수있는 서비스를 만드는 유일한 방법입니다. 이전 to 메소드와 달리, 정의 된 this. $ get () 함수 정의에서 인젝터 블을 설정합니다.

-3

구문 설탕은 차이점 입니다. 공급자 만 필요합니다. 즉, 공급자만이 실제 각도이며 다른 모든 공급자가 파생됩니다 (코드를 줄이기 위해). Value ()라는 간단한 버전도 있습니다.이 버전은 계산이나 함수없이 값만 반환합니다. 균등 한 가치는 공급자로부터 도출됩니다!

그렇다면 왜 그러한 합병증이 발생합니까? 왜 우리는 공급자를 사용하고 다른 모든 것을 잊을 수 없습니까? 쉽게 코드를 작성하고 더 잘 의사 소통 할 수 있도록 도와줍니다. 그리고 멍청한 뺨의 대답은 틀이 복잡할수록 프레임 워크가 더 잘 팔릴 것입니다.


  • value = Value를 반환 할 수있는 공급자
  • 인스턴스화하고 반환 할 수있는 공급자 = Factory (+ Value)
  • 인스턴스화 + 무언가를 할 수있는 제공자 = 서비스 (+ Factory, + Value)
  • 공급자 = $ get (+ Factory, + Service, + Value)라는 속성을 포함해야합니다.

각도 주입은이 결론에 도달하는 첫 번째 힌트를줍니다.

"$ injector는 팩토리가 아닌 제공자가 아닌 서비스 제공자가 정의한 오브젝트 인스턴스를 검색하는 데 사용됩니다 .

"각도 서비스는 서비스 팩토리에 의해 생성됩니다. 이러한 서비스 팩토리는 서비스 제공자에 의해 생성되는 함수입니다. 서비스 제공자는 생성자 함수입니다. 인스턴스화되면 속성을 포함해야합니다. 서비스 팩토리 기능을 보유한 $ get이라고합니다. "

따라서 마스터 제공자와 인젝터 및 모든 것이 제자리에 놓입니다. 그리고 IServiceProvider에서 상속하여 $ get을 공급자에서 구현할 수 있으면 Typescript에서 흥미로워집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.