AngularJS: Dịch vụ so với nhà cung cấp vs nhà máy


3319

Sự khác nhau giữa là gì Service, ProviderFactorytại AngularJS?


244
Tôi thấy rằng tất cả các thuật ngữ Angular là đáng sợ cho người mới bắt đầu. Chúng tôi bắt đầu với chiếc áo này dễ hiểu hơn cho các lập trình viên của chúng tôi khi học Angular demisx.github.io/angularjs/2014/09/14/ . Hy vọng điều này sẽ giúp đội của bạn quá.
demisx

7
Theo tôi, cách tốt nhất để hiểu sự khác biệt là sử dụng tài liệu riêng của Angular: docs.angularjs.org/guide/providers, nó được giải thích rất tốt và sử dụng một ví dụ đặc biệt để giúp bạn hiểu về nó.
Rafael Merlin

3
@Blaise Cảm ơn bạn! Theo nhận xét của tôi trong bài đăng, tôi đã cố ý bỏ qua, vì 99% trường hợp sử dụng từ kinh nghiệm của tôi có thể được xử lý thành công thông qua service.factory. Không muốn làm phức tạp thêm chủ đề này.
demisx

3
Tôi thấy cuộc thảo luận này cũng rất hữu ích stackoverflow.com/questions/18939709/ từ
Anand Gupta

3
Dưới đây là một số câu trả lời tốt về cách thứcservices,factoriesprovidershoạt động.
Mistalis

Câu trả lời:


2866

Từ danh sách gửi thư của AngularJS, tôi đã nhận được một chủ đề tuyệt vời giải thích dịch vụ so với nhà máy và nhà cung cấp và việc sử dụng thuốc tiêm của họ. Tổng hợp các câu trả lời:

Dịch vụ

Cú pháp: module.service( 'serviceName', function );
Kết quả: Khi khai báo serviceName dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp một thể hiện của hàm. Nói cách khácnew FunctionYouPassedToService() .

Các nhà máy

Cú pháp: module.factory( 'factoryName', function );
Kết quả: Khi khai báo FactoryName là đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi tham chiếu hàm được truyền cho module.factory .

Nhà cung cấp

Cú pháp: module.provider( 'providerName', function );
Kết quả: Khi khai báo CarrierName là đối số có thể tiêm, bạn sẽ được cung cấp(new ProviderFunction()).$get() . Hàm constructor được khởi tạo trước khi phương thức $ get được gọi - ProviderFunctionlà tham chiếu hàm được truyền cho module.provider.

Các nhà cung cấp có lợi thế là họ có thể được cấu hình trong giai đoạn cấu hình mô-đun.

Xem ở đây để biết mã được cung cấp.

Đây là một lời giải thích tuyệt vời hơn nữa của Misko:

provide.value('a', 123);

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

Trong trường hợp này, người tiêm chỉ cần trả về giá trị như hiện tại. Nhưng nếu bạn muốn tính giá trị thì sao? Sau đó sử dụng một nhà máy

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

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

Vì vậy, factorylà một chức năng chịu trách nhiệm tạo ra giá trị. Lưu ý rằng chức năng của nhà máy có thể yêu cầu các phụ thuộc khác.

Nhưng nếu bạn muốn trở thành OO nhiều hơn và có một lớp gọi là Greeter thì sao?

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

Sau đó, để khởi tạo bạn sẽ phải viết

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

Sau đó, chúng ta có thể yêu cầu 'người chào' trong bộ điều khiển như thế này

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

Nhưng đó là cách quá dài dòng. Một cách ngắn hơn để viết này sẽ làprovider.service('greeter', Greeter);

Nhưng nếu chúng ta muốn cấu hình Greeterlớp trước khi tiêm thì sao? Sau đó chúng ta có thể viết

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

Sau đó chúng ta có thể làm điều này:

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

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

Là một mặt lưu ý, service, factory, và valuetất cả đều có nguồn gốc từ nhà cung cấp.

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
Xem thêm stackoverflow.com/a/13763886/215945 trong đó thảo luận về sự khác biệt giữa dịch vụ và nhà máy.
Mark Rajcok

3
Trong chỉnh sửa 611 tôi đã thêm việc sử dụng các hằng số và giá trị góc. Để chứng minh sự khác biệt của người khác đã được hiển thị. jsbin.com/ohamub/611/edit
Nick

17
Mặc dù một dịch vụ được gọi bằng cách tạo một thể hiện của hàm. Nó thực sự được tạo ra chỉ một lần cho mỗi kim phun mà làm cho nó giống như singleton. docs.angularjs.org/guide/dev_guide.service.creating_service
angelokh

33
Ví dụ này có thể đáng kinh ngạc nếu nó sử dụng một ví dụ thực tế rõ ràng. Tôi bị lạc khi cố gắng tìm hiểu quan điểm của mọi thứ như thế nào toEqualgreeter.Greetlà gì. Tại sao không sử dụng một cái gì đó hơi thực tế và dễ hiểu hơn?
Kyle Pennell

5
Sử dụng hàm mong đợi () là một lựa chọn kém để giải thích điều gì đó. Sử dụng mã thế giới thực lần sau.
Craig

812

Demo Fiddle

Ví dụ "Hello world" với 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
Không thisthay đổi bối cảnh trong $getchức năng? - bạn không còn đề cập đến nhà cung cấp khởi tạo trong chức năng đó.
Nate-Wilkins

12
@Nate: thisthực tế không thay đổi ngữ cảnh, bởi vì cái được gọi là new Provider(). $ Get (), Providerhàm được truyền đến đâu app.provider. Điều đó có nghĩa $get()là đang được gọi là một phương thức trên được xây dựng Provider, vì vậy thissẽ đề cập đến Providernhư ví dụ gợi ý.
Brandon

1
@Brandon Ohh ok đó là gọn gàng rồi. Nhầm lẫn từ cái nhìn đầu tiên - cảm ơn đã làm rõ!
Nate-Wilkins

3
Tại sao tôi nhận được Unknown provider: helloWorldProvider <- helloWorldkhi chạy này cục bộ? Nhận xét nó, lỗi tương tự cho 2 ví dụ khác. Có một số cấu hình nhà cung cấp ẩn? (Angular 1.0.8) - Đã tìm thấy: stackoverflow.com/questions/12339272/iêu
Antoine

4
Là lý do tại sao @Antoine gặp lỗi "Unknown cung cấp: helloWorldProvider" vì trong mã .config của bạn, bạn sử dụng 'helloWorldProvider', nhưng khi bạn xác định nhà cung cấp trong myApp.provider ('helloWorld', function ()), bạn sẽ sử dụng 'Chào thế giới'? Nói cách khác, trong mã cấu hình của bạn, làm thế nào angular biết bạn đang đề cập đến nhà cung cấp helloWorld? Cảm ơn
jmtoung

645

TL; DR

1) Khi bạn đang sử dụng Factory, bạn tạo một đối tượng, thêm thuộc tính cho nó, sau đó trả về cùng một đối tượng đó. Khi bạn chuyển nhà máy này vào bộ điều khiển của mình, các thuộc tính đó trên đối tượng sẽ có sẵn trong bộ điều khiển đó thông qua nhà máy của bạn.

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) Khi bạn đang sử dụng Dịch vụ , AngularJS sẽ khởi tạo nó phía sau hậu trường với từ khóa 'mới'. Do đó, bạn sẽ thêm thuộc tính vào 'cái này' và dịch vụ sẽ trả về 'cái này'. Khi bạn chuyển dịch vụ vào bộ điều khiển của mình, các thuộc tính đó trên 'this' sẽ có sẵn trên bộ điều khiển đó thông qua dịch vụ của bạn.

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

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



3) Nhà cung cấp là dịch vụ duy nhất bạn có thể chuyển vào hàm .config (). Sử dụng nhà cung cấp khi bạn muốn cung cấp cấu hình toàn mô-đun cho đối tượng dịch vụ của mình trước khi cung cấp.

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



Không TL; DR

1) Nhà máy của
nhà máy là cách phổ biến nhất để tạo và định cấu hình dịch vụ. Thực sự không có nhiều hơn những gì TL; DR nói. Bạn chỉ cần tạo một đối tượng, thêm thuộc tính cho nó, sau đó trả lại cùng một đối tượng đó. Sau đó, khi bạn chuyển nhà máy vào bộ điều khiển của mình, các thuộc tính đó trên đối tượng sẽ có sẵn trong bộ điều khiển đó thông qua nhà máy của bạn. Một ví dụ rộng hơn là dưới đây.

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

Bây giờ, bất kỳ thuộc tính nào chúng tôi đính kèm vào 'dịch vụ' sẽ có sẵn cho chúng tôi khi chúng tôi chuyển 'myFactory' vào bộ điều khiển của chúng tôi.

Bây giờ, hãy thêm một số biến 'riêng tư' vào chức năng gọi lại của chúng tôi. Chúng không thể truy cập trực tiếp từ bộ điều khiển, nhưng cuối cùng chúng tôi sẽ thiết lập một số phương thức getter / setter trên 'dịch vụ' để có thể thay đổi các biến 'riêng tư' này khi cần.

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

Ở đây bạn sẽ nhận thấy chúng tôi không gắn các biến / chức năng đó vào 'dịch vụ'. Chúng tôi chỉ đơn giản là tạo chúng để sử dụng hoặc sửa đổi chúng sau này.

  • baseUrl là URL cơ sở mà API iTunes yêu cầu
  • _artist là nghệ sĩ chúng tôi muốn tìm kiếm
  • _finalUrl là URL cuối cùng và được xây dựng đầy đủ để chúng tôi thực hiện cuộc gọi tới iTunes
  • makeUrl là một chức năng sẽ tạo và trả lại URL thân thiện với iTunes của chúng tôi.

Bây giờ, các biến và hàm trợ giúp / riêng tư của chúng ta đã sẵn sàng, hãy thêm một số thuộc tính vào đối tượng 'dịch vụ'. Bất cứ điều gì chúng tôi đưa vào 'dịch vụ' đều có thể được sử dụng trực tiếp bên trong bất kỳ bộ điều khiển nào chúng tôi chuyển 'myFactory' vào.

Chúng ta sẽ tạo các phương thức setArtist và getArtist chỉ đơn giản là trả về hoặc đặt nghệ sĩ. Chúng tôi cũng sẽ tạo một phương thức sẽ gọi API iTunes bằng URL được tạo của chúng tôi. Phương pháp này sẽ trả lại một lời hứa sẽ thực hiện khi dữ liệu đã quay trở lại từ API iTunes. Nếu bạn chưa có nhiều kinh nghiệm sử dụng lời hứa trong AngularJS, tôi khuyên bạn nên thực hiện một cuộc lặn sâu vào chúng.

Dưới đây setArtist chấp nhận một nghệ sĩ và cho phép bạn đặt nghệ sĩ. getArtist trả lại nghệ sĩ. callItunes trước tiên gọi makeUrl () để tạo URL chúng tôi sẽ sử dụng với yêu cầu $ http của chúng tôi. Sau đó, nó thiết lập một đối tượng lời hứa, thực hiện một yêu cầu $ http với url cuối cùng của chúng tôi, sau đó vì $ http trả lại một lời hứa, chúng tôi có thể gọi .success hoặc .error sau yêu cầu của chúng tôi. Sau đó, chúng tôi giải quyết lời hứa của chúng tôi với dữ liệu iTunes hoặc chúng tôi từ chối nó với thông báo 'Có lỗi'.

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

Bây giờ nhà máy của chúng tôi đã hoàn thành. Bây giờ chúng tôi có thể đưa 'myFactory' vào bất kỳ bộ điều khiển nào và sau đó chúng tôi sẽ có thể gọi các phương thức mà chúng tôi đã gắn vào đối tượng dịch vụ của mình (setArtist, getArtist và 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);
      })
  }
});

Trong bộ điều khiển ở trên, chúng tôi đang tiêm dịch vụ 'myFactory'. Sau đó, chúng tôi đặt thuộc tính trên đối tượng $ scope với dữ liệu từ 'myFactory'. Mã khó khăn duy nhất ở trên là nếu bạn chưa bao giờ thực hiện lời hứa trước đó. Vì callItunes đang trả lại một lời hứa, chúng tôi có thể sử dụng phương thức .then () và chỉ đặt $ scope.data.artistData sau khi lời hứa của chúng tôi được thực hiện với dữ liệu iTunes. Bạn sẽ nhận thấy bộ điều khiển của chúng tôi rất "mỏng" (Đây là một cách thực hành mã hóa tốt). Tất cả dữ liệu logic và liên tục của chúng tôi được đặt trong dịch vụ của chúng tôi, không phải trong bộ điều khiển của chúng tôi.

2) Dịch vụ
Có lẽ điều lớn nhất cần biết khi xử lý việc tạo Dịch vụ là nó được khởi tạo với từ khóa 'mới'. Đối với bạn các chuyên gia JavaScript, điều này sẽ cung cấp cho bạn một gợi ý lớn về bản chất của mã. Đối với những người bạn có nền tảng hạn chế về JavaScript hoặc cho những người không quá quen thuộc với từ khóa 'mới' thực sự làm gì, hãy xem xét một số nguyên tắc cơ bản về JavaScript cuối cùng sẽ giúp chúng tôi hiểu bản chất của Dịch vụ.

Để thực sự thấy những thay đổi xảy ra khi bạn gọi một hàm với từ khóa 'mới', hãy tạo một hàm và gọi nó bằng từ khóa 'mới', sau đó hãy cho biết trình thông dịch làm gì khi thấy từ khóa 'mới'. Kết quả cuối cùng sẽ giống nhau.

Trước tiên hãy tạo Trình xây dựng của chúng tôi.

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

Đây là một hàm xây dựng JavaScript điển hình. Bây giờ, bất cứ khi nào chúng ta gọi hàm Person bằng từ khóa 'mới', 'this' sẽ bị ràng buộc với đối tượng mới được tạo.

Bây giờ, hãy thêm một phương thức vào nguyên mẫu của Người của chúng tôi để nó sẽ có sẵn trên mọi phiên bản của 'Người' của chúng tôi.

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

Bây giờ, vì chúng tôi đặt hàm sayName trên nguyên mẫu, mọi phiên bản của Person sẽ có thể gọi hàm sayName để cảnh báo tên của cá thể đó.

Bây giờ chúng ta có hàm xây dựng Person và hàm sayName trên nguyên mẫu của nó, hãy thực sự tạo một thể hiện của Person sau đó gọi hàm sayName.

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

Vì vậy, tất cả các mã cùng nhau để tạo một hàm tạo Person, thêm một hàm vào nguyên mẫu của nó, tạo một cá thể Person, và sau đó gọi hàm trên nguyên mẫu của nó trông như thế này.

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’

Bây giờ hãy xem điều gì đang thực sự xảy ra khi bạn sử dụng từ khóa 'mới' trong JavaScript. Điều đầu tiên bạn cần lưu ý là sau khi sử dụng 'new' trong ví dụ của chúng tôi, chúng tôi có thể gọi một phương thức (sayName) trên 'tyler' giống như đó là một đối tượng - đó là vì nó là. Vì vậy, trước tiên, chúng ta biết rằng hàm tạo Person của chúng ta đang trả về một đối tượng, cho dù chúng ta có thể thấy điều đó trong mã hay không. Thứ hai, chúng ta biết rằng vì hàm sayName của chúng ta nằm trên nguyên mẫu và không trực tiếp trên cá thể Person, nên đối tượng mà hàm Person đang trả về phải được ủy quyền cho nguyên mẫu của nó khi tra cứu thất bại. Nói một cách đơn giản hơn, khi chúng ta gọi tyler.sayName () trình thông dịch nói rằng OK OK, tôi sẽ xem xét đối tượng 'tyler' mà chúng ta vừa tạo, định vị hàm sayName, sau đó gọi nó. Đợi một chút, tôi không thấy nó ở đây - tất cả những gì tôi thấy là tên và tuổi, Hãy để tôi kiểm tra nguyên mẫu. Yup, có vẻ như nó trên nguyên mẫu, hãy để tôi gọi nó.

Dưới đây là mã cho cách bạn có thể nghĩ về những gì từ khóa 'mới' thực sự đang làm trong JavaScript. Về cơ bản, đây là một ví dụ mã của đoạn văn trên. Tôi đã đặt 'chế độ xem trình thông dịch' hoặc cách trình thông dịch nhìn thấy mã bên trong các ghi chú.

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

Bây giờ có kiến ​​thức về những gì từ khóa 'mới' thực sự làm trong JavaScript, việc tạo một Dịch vụ trong AngularJS sẽ dễ hiểu hơn.

Điều lớn nhất cần hiểu khi tạo Dịch vụ là biết rằng Dịch vụ được khởi tạo với từ khóa 'mới'. Kết hợp kiến ​​thức đó với các ví dụ của chúng tôi ở trên, giờ đây bạn sẽ nhận ra rằng bạn sẽ trực tiếp đính kèm các thuộc tính và phương thức của mình vào 'cái này' mà sau đó sẽ được trả về từ chính Dịch vụ. Chúng ta hãy xem điều này trong hành động.

Không giống như những gì chúng ta đã làm với ví dụ Factory, chúng ta không cần tạo một đối tượng sau đó trả về đối tượng đó bởi vì, như đã đề cập nhiều lần trước đó, chúng ta đã sử dụng từ khóa 'mới' để trình thông dịch sẽ tạo đối tượng đó, ủy thác cho nó đó là nguyên mẫu, sau đó trả lại cho chúng tôi mà không cần chúng tôi phải thực hiện công việc.

Trước tiên, hãy tạo chức năng 'riêng tư' và trợ giúp của chúng tôi. Điều này sẽ trông rất quen thuộc vì chúng tôi đã làm điều tương tự chính xác với nhà máy của chúng tôi. Tôi sẽ không giải thích mỗi dòng làm gì ở đây vì tôi đã làm điều đó trong ví dụ về nhà máy, nếu bạn bối rối, hãy đọc lại ví dụ về nhà máy.

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

Bây giờ, chúng tôi sẽ đính kèm tất cả các phương thức sẽ có trong bộ điều khiển của chúng tôi vào 'cái này'.

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

});

Bây giờ giống như trong nhà máy của chúng tôi, setArtist, getArtist và callItunes sẽ có sẵn trong bất kỳ bộ điều khiển nào chúng tôi chuyển myService vào. Đây là bộ điều khiển myService (gần giống hệt như bộ điều khiển nhà máy của chúng tôi).

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

Giống như tôi đã đề cập trước đây, một khi bạn thực sự hiểu những gì 'mới', Dịch vụ gần như giống hệt với các nhà máy ở AngularJS.

3) Nhà cung cấp

Điều lớn nhất cần nhớ về Nhà cung cấp là họ là dịch vụ duy nhất mà bạn có thể chuyển vào phần app.config trong ứng dụng của mình. Điều này có tầm quan trọng rất lớn nếu bạn cần thay đổi một phần đối tượng dịch vụ của mình trước khi nó có sẵn ở mọi nơi khác trong ứng dụng của bạn. Mặc dù rất giống với Dịch vụ / Nhà máy, có một vài điểm khác biệt mà chúng ta sẽ thảo luận.

Đầu tiên, chúng tôi thiết lập Nhà cung cấp của mình theo cách tương tự như chúng tôi đã làm với Dịch vụ và Nhà máy của mình. Các biến dưới đây là chức năng 'riêng tư' và trợ giúp của chúng tôi.

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

* Một lần nữa nếu bất kỳ phần nào của đoạn mã trên gây nhầm lẫn, hãy xem phần Factory nơi tôi giải thích tất cả những gì nó làm chi tiết hơn.

Bạn có thể nghĩ về Nhà cung cấp có ba phần. Phần đầu tiên là các biến / hàm 'riêng tư' sẽ được sửa đổi / thiết lập sau (hiển thị ở trên). Phần thứ hai là các biến / hàm sẽ có sẵn trong hàm app.config của bạn và do đó có sẵn để thay đổi trước khi chúng có sẵn ở bất kỳ nơi nào khác (cũng được hiển thị ở trên). Điều quan trọng cần lưu ý là các biến đó cần được gắn vào từ khóa 'this'. Trong ví dụ của chúng tôi, chỉ 'thingFromConfig' sẽ có sẵn để thay đổi trong app.config. Phần thứ ba (hiển thị bên dưới) là tất cả các biến / hàm sẽ có trong bộ điều khiển của bạn khi bạn chuyển dịch vụ 'myProvider' vào bộ điều khiển cụ thể đó.

Khi tạo một dịch vụ với Nhà cung cấp, các thuộc tính / phương thức duy nhất có sẵn trong bộ điều khiển của bạn là các thuộc tính / phương thức được trả về từ hàm $ get (). Đoạn mã dưới đây đặt $ get vào 'this' (mà chúng ta biết cuối cùng sẽ được trả về từ hàm đó). Bây giờ, hàm $ get trả về tất cả các phương thức / thuộc tính mà chúng ta muốn có sẵn trong bộ điều khiển. Đây là một ví dụ mã.

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

Bây giờ mã nhà cung cấp đầy đủ trông như thế này

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

Bây giờ giống như trong nhà máy và Dịch vụ của chúng tôi, setArtist, getArtist và callItunes sẽ có sẵn trong bất kỳ bộ điều khiển nào chúng tôi chuyển myProvider vào. Đây là bộ điều khiển myProvider (gần giống hệt như bộ điều khiển nhà máy / dịch vụ của chúng tôi).

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

Như đã đề cập trước đó, toàn bộ điểm tạo ra một dịch vụ với Nhà cung cấp là có thể thay đổi một số biến thông qua chức năng app.config trước khi đối tượng cuối cùng được chuyển đến phần còn lại của ứng dụng. Hãy xem một ví dụ về điều đó.

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

Bây giờ bạn có thể thấy 'thingFromConfig' là chuỗi rỗng trong nhà cung cấp của chúng tôi, nhưng khi nó xuất hiện trong DOM, nó sẽ là 'Câu này đã được đặt ra'.


11
Phần duy nhất còn thiếu trong bài viết xuất sắc này là những lợi thế tương đối của việc sử dụng dịch vụ so với nhà máy; được giải thích rõ ràng trong câu trả lời được chấp nhận bởi Lior
vô cùng

2
FWIW (có thể không nhiều), đây là một blogger có vấn đề với Angular và không thích nhà cung cấpProvider codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
Cú đấm của 'các bậc thầy về JavaScript' thật ranh mãnh. : DI nghĩ rằng câu trả lời này sẽ xóa mọi thứ rất nhiều. Tuyệt vời bằng văn bản.
amarmishra

4
TLDR của bạn cần một TLDR.
JensB

3
@JensB tl; dr - Tìm hiểu Phản ứng.
Tyler McGinnis

512

Tất cả các dịch vụ là singletons ; họ được khởi tạo một lần cho mỗi ứng dụng. Chúng có thể thuộc bất kỳ loại nào , cho dù đó là kiểu nguyên thủy, nghĩa đen, hàm hoặc thậm chí là một thể hiện của loại tùy chỉnh.

Các value, factory, service, constant, và providercác phương pháp đều là các nhà cung cấp. Họ dạy cho In phun cách khởi tạo Dịch vụ.

Cao nhất, nhưng cũng toàn diện nhất là một công thức Nhà cung cấp. Các Bốn còn lại loại recipe - Giá trị, Nhà máy, dịch vụ và Constant - chỉ là cú pháp đường trên đầu trang của một công thức cung cấp dịch vụ .

  • Các Recipe Giá trị là trường hợp đơn giản nhất, nơi bạn nhanh chóng Dịch vụ bản thân và cung cấp các giá trị được thuyết minh để các vòi phun.
  • Công thức Factory cung cấp cho In phun một chức năng của nhà máy mà nó gọi khi cần khởi tạo dịch vụ. Khi được gọi, hàm nhà máy sẽ tạo và trả về thể hiện của dịch vụ. Các phụ thuộc của Dịch vụ được thêm vào dưới dạng đối số của hàm. Vì vậy, sử dụng công thức này thêm các khả năng sau đây:
    • Khả năng sử dụng các dịch vụ khác (có phụ thuộc)
    • Khởi tạo dịch vụ
    • Trì hoãn / lười khởi tạo
  • Công thức dịch vụ gần giống như công thức Factory, nhưng ở đây, In phun gọi một hàm tạo với toán tử mới thay vì hàm nhà máy.
  • Công thức cung cấp thường là quá mức cần thiết . Nó thêm một lớp gián tiếp bằng cách cho phép bạn định cấu hình việc tạo nhà máy.

    Bạn chỉ nên sử dụng công thức Nhà cung cấp khi bạn muốn hiển thị API cho cấu hình toàn ứng dụng phải được thực hiện trước khi ứng dụng bắt đầu. Điều này thường chỉ thú vị đối với các dịch vụ có thể sử dụng lại mà hành vi của chúng có thể cần thay đổi đôi chút giữa các ứng dụng.

  • Công thức Constant giống như công thức Giá trị ngoại trừ nó cho phép bạn xác định các dịch vụ có sẵn trong giai đoạn cấu hình . Sớm hơn các dịch vụ được tạo bằng công thức Giá trị. Không giống như các giá trị, chúng không thể được trang trí bằng cách sử dụng decorator.
Xem tài liệu của nhà cung cấp .


2
Vì vậy, dịch vụ và nhà máy về cơ bản là giống nhau? Sử dụng một trong những cái khác cung cấp không có gì ngoài cú pháp thay thế?
Matt

2
@Matt, vâng, dịch vụ là một cách ngắn gọn khi bạn đã có chức năng của riêng mình mà bạn muốn trưng ra như một dịch vụ. Từ tài liệu: myApp.factory ('unicornLauncher', ["apiToken", function (apiToken) {trả lại UnicornLauncher mới (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
janek

5
@joshperry Là một người mới, tôi đã hiểu được sự khác biệt giữa dịch vụ và nhà máy trong một thời gian. Tôi đồng ý đây là câu trả lời tốt nhất bao giờ hết! Tôi hiểu dịch vụ là một lớp dịch vụ (ví dụ: lớp mã hóa / giải mã), có thể có một số thuộc tính riêng. Và nhà máy cung cấp một tập hợp các phương pháp trợ giúp không trạng thái.
stanleyxu2005 14/03/2015

3
Các ví dụ của Yaa trong các câu trả lời khác ở trên không giải thích được rõ ràng về sự khác biệt cốt lõi của các dịch vụ và nhà cung cấp, đó là những gì được tiêm vào thời điểm khi các công thức này được khởi tạo.
Ashish Singh

223

Hiểu nhà máy, dịch vụ và nhà cung cấp AngularJS

Tất cả những thứ này được sử dụng để chia sẻ các đối tượng singleton có thể tái sử dụng. Nó giúp chia sẻ mã có thể sử dụng lại trên ứng dụng / các thành phần / mô-đun khác nhau của bạn.

Từ Dịch vụ / Nhà máy Docs :

  • Khởi tạo nhanh chóng - Angular chỉ khởi tạo một dịch vụ / nhà máy khi một thành phần ứng dụng phụ thuộc vào nó.
  • Singletons - Mỗi thành phần phụ thuộc vào một dịch vụ sẽ tham chiếu đến một thể hiện duy nhất được tạo bởi nhà máy dịch vụ.

Nhà máy

Một nhà máy là chức năng nơi bạn có thể thao tác / thêm logic trước khi tạo một đối tượng, sau đó đối tượng mới được tạo sẽ được trả về.

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

Sử dụng

Nó có thể chỉ là một tập hợp các hàm như một lớp. Do đó, nó có thể được khởi tạo trong các bộ điều khiển khác nhau khi bạn tiêm nó vào bên trong các chức năng điều khiển / nhà máy / chỉ thị của bạn. Nó được khởi tạo chỉ một lần cho mỗi ứng dụng.

Dịch vụ

Đơn giản là trong khi nhìn vào các dịch vụ nghĩ về nguyên mẫu mảng. Dịch vụ là một chức năng khởi tạo một đối tượng mới bằng cách sử dụng từ khóa 'mới'. Bạn có thể thêm các thuộc tính và chức năng cho một đối tượng dịch vụ bằng cách sử dụng thistừ khóa. Không giống như một nhà máy, nó không trả về bất cứ thứ gì (nó trả về một đối tượng có chứa các phương thức / thuộc tính).

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

Sử dụng

Sử dụng nó khi bạn cần chia sẻ một đối tượng trong suốt ứng dụng. Ví dụ: chi tiết người dùng được xác thực, phương pháp / dữ liệu có thể chia sẻ, chức năng Utility, v.v.

Các nhà cung cấp

Một nhà cung cấp được sử dụng để tạo một đối tượng dịch vụ có thể cấu hình. Bạn có thể định cấu hình cài đặt dịch vụ từ chức năng cấu hình. Nó trả về một giá trị bằng cách sử dụng $get()hàm. Các $getchức năng được thực hiện vào giai đoạn chạy trong góc.

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

Sử dụng

Khi bạn cần cung cấp cấu hình mô-đun cho đối tượng dịch vụ của mình trước khi cung cấp nó, vd. giả sử bạn muốn đặt URL API trên cơ sở Môi trường của bạn như dev, stagehoặcprod

GHI CHÚ

Chỉ nhà cung cấp sẽ có sẵn trong giai đoạn cấu hình của góc, trong khi dịch vụ & nhà máy thì không.

Hy vọng điều này đã làm sáng tỏ sự hiểu biết của bạn về Nhà máy, Dịch vụ và Nhà cung cấp .


1
Tôi sẽ làm gì nếu tôi muốn có một dịch vụ với giao diện cụ thể, nhưng có hai cách triển khai khác nhau và đưa từng dịch vụ vào một bộ điều khiển nhưng gắn với các trạng thái khác nhau bằng ui-router? ví dụ: thực hiện cuộc gọi từ xa ở một trạng thái, nhưng ghi vào bộ nhớ cục bộ thay vì ở trạng thái khác. Các tài liệu của nhà cung cấp nói để sử dụng 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, vì vậy không có âm thanh, phải không?
qix

191

Đối với tôi, sự mặc khải đến khi tôi nhận ra rằng tất cả chúng đều hoạt động theo cùng một cách: bằng cách chạy một cái gì đó một lần , lưu trữ giá trị họ nhận được, và sau đó ho lên cùng một giá trị được lưu trữ khi được tham chiếu thông qua tiêm phụ thuộc .

Nói rằng chúng tôi có:

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

Sự khác biệt giữa ba là:

  1. aGiá trị được lưu trữ đến từ việc chạy fn.
  2. bGiá trị được lưu trữ đến từ newing fn.
  3. c'giá trị s lưu trữ xuất phát từ đầu tiên nhận được một thể hiện bởi newing fn, và sau đó chạy một $getphương pháp sơ thẩm.

Điều đó có nghĩa là có một cái gì đó giống như một đối tượng bộ đệm trong AngularJS, giá trị của mỗi lần tiêm chỉ được gán một lần, khi chúng được tiêm lần đầu tiên và ở đâu:

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

Đây là lý do tại sao chúng tôi sử dụng thistrong các dịch vụ và xác định một this.$gettrong các nhà cung cấp.


2
Tôi cũng thích câu trả lời này nhất. Quan điểm của tất cả chúng là cung cấp quyền truy cập vào một đối tượng bất cứ khi nào cần thông qua DI. Thông thường bạn đang làm tốt với factorys. Lý do duy nhất servicetồn tại là các ngôn ngữ như CoffeeScript, TypeScript, ES6, v.v. để bạn có thể sử dụng cú pháp lớp của chúng. Bạn chỉ cần providers nếu mô-đun của bạn được sử dụng trong một số ứng dụng với các cài đặt khác nhau bằng cách sử dụng app.config(). Nếu dịch vụ của bạn là một singleton thuần túy hoặc có thể tạo các phiên bản của một cái gì đó chỉ phụ thuộc vào việc triển khai của bạn.
Andreas Linnert

137

Dịch vụ vs nhà cung cấp vs nhà máy:

Tôi đang cố gắng để giữ cho nó đơn giản. Đó là tất cả về khái niệm JavaScript cơ bản.

Trước hết, hãy nói về các dịch vụ trong AngularJS!

Dịch vụ là gì: Trong AngularJS, Dịch vụkhông là gì ngoài một đối tượng JavaScript đơn lẻ có thể lưu trữ một số phương thức hoặc thuộc tính hữu ích. Đối tượng singleton này được tạo trên cơ sở ngApp (ứng dụng Angular) và nó được chia sẻ giữa tất cả các bộ điều khiển trong ứng dụng hiện tại. Khi Angularjs khởi tạo một đối tượng dịch vụ, nó đăng ký đối tượng dịch vụ này với một tên dịch vụ duy nhất. Vì vậy, mỗi khi chúng ta cần phiên bản dịch vụ, Angular tìm kiếm sổ đăng ký cho tên dịch vụ này và nó trả về tham chiếu đến đối tượng dịch vụ. Để chúng ta có thể gọi phương thức, truy cập các thuộc tính, vv trên đối tượng dịch vụ. Bạn có thể có câu hỏi liệu bạn cũng có thể đặt các thuộc tính, phương thức vào đối tượng phạm vi của bộ điều khiển! Vậy tại sao bạn cần đối tượng dịch vụ? Câu trả lời là: dịch vụ được chia sẻ giữa nhiều phạm vi điều khiển. Nếu bạn đặt một số thuộc tính / phương thức trong đối tượng phạm vi của bộ điều khiển, nó sẽ chỉ khả dụng cho phạm vi hiện tại.

Vì vậy, nếu có ba phạm vi điều khiển, hãy để nó là bộ điều khiểnA, bộ điều khiểnB và bộ điều khiển, tất cả sẽ chia sẻ cùng một thể hiện dịch vụ.

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

Làm thế nào để tạo ra một dịch vụ?

AngularJS cung cấp các phương pháp khác nhau để đăng ký một dịch vụ. Ở đây chúng tôi sẽ tập trung vào ba phương thức nhà máy (..), dịch vụ (..), nhà cung cấp (..);

Sử dụng liên kết này để tham khảo mã

Chức năng của nhà máy:

Chúng ta có thể định nghĩa một chức năng nhà máy như dưới đây.

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

AngularJS cung cấp phương thức 'Factory (' serviceName ', fnFactory)' trong đó có hai tham số, serviceName và hàm JavaScript. Angular tạo cá thể dịch vụ bằng cách gọi hàm fnFactory () như bên dưới.

var serviceInstace = fnFactory();

Hàm thông qua có thể định nghĩa một đối tượng và trả về đối tượng đó. AngularJS chỉ lưu trữ tham chiếu đối tượng này đến một biến được truyền dưới dạng đối số đầu tiên. Bất cứ điều gì được trả về từ fnFactory sẽ bị ràng buộc với serviceInstance. Thay vì trả về đối tượng, chúng ta cũng có thể trả về hàm, các giá trị, v.v., Dù chúng ta sẽ trả về, sẽ có sẵn cho thể hiện dịch vụ.

Thí dụ:

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

Chức năng dịch vụ:

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

Đó là một cách khác, chúng ta có thể đăng ký một dịch vụ. Sự khác biệt duy nhất là cách AngularJS cố gắng khởi tạo đối tượng dịch vụ. Lần này góc sử dụng từ khóa 'mới' và gọi hàm xây dựng một cái gì đó như dưới đây.

var serviceInstance = new fnServiceConstructor();

Trong hàm constructor, chúng ta có thể sử dụng từ khóa 'this' để thêm thuộc tính / phương thức vào đối tượng dịch vụ. thí dụ:

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

Chức năng nhà cung cấp:

Hàm Carrier () là một cách khác để tạo dịch vụ. Hãy để chúng tôi quan tâm để tạo ra một dịch vụ chỉ hiển thị một số thông điệp chào mừng đến người dùng. Nhưng chúng tôi cũng muốn cung cấp một chức năng để người dùng có thể đặt thông điệp chào mừng của riêng họ. Về mặt kỹ thuật, chúng tôi muốn tạo ra các dịch vụ cấu hình. Làm thế nào chúng ta có thể làm điều này ? Phải có một cách để ứng dụng có thể chuyển thông điệp chào hỏi tùy chỉnh của họ và Angularjs sẽ cung cấp cho chức năng nhà máy / nhà xây dựng tạo ra thể hiện dịch vụ của chúng tôi. Trong trường hợp như vậy, hàm cung cấp () thực hiện công việc. sử dụng hàm nhà cung cấp () chúng ta có thể tạo các dịch vụ cấu hình.

Chúng tôi có thể tạo các dịch vụ có thể định cấu hình bằng cú pháp của nhà cung cấp như được đưa ra dưới đây.

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

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

Làm thế nào để cú pháp nhà cung cấp nội bộ làm việc?

Đối tượng 1.Provider được tạo bằng hàm constructor mà chúng ta đã định nghĩa trong hàm nhà cung cấp.

var serviceProvider = new serviceProviderConstructor();

2. Hàm chúng ta đã truyền trong app.config (), được thực thi. Đây được gọi là giai đoạn cấu hình và ở đây chúng tôi có cơ hội tùy chỉnh dịch vụ của mình.

configureService(serviceProvider);

3. Ví dụ dịch vụ cuối cùng được tạo bằng cách gọi phương thức $ get của serviceProvider.

serviceInstance = serviceProvider.$get()

Mã mẫu để tạo dịch vụ bằng cú pháp cung cấp:

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

Trình diễn làm việc

Tóm lược:


Nhà máy sử dụng chức năng của nhà máy trả về một thể hiện dịch vụ. serviceInstance = fnFactory ();

Dịch vụ sử dụng hàm xây dựng và Angular gọi hàm xây dựng này bằng từ khóa 'mới' để tạo phiên bản dịch vụ. serviceInstance = new fnServiceConstructor ();

Nhà cung cấp xác định chức năng của nhà cung cấp, công cụ của nhà cung cấp này cung cấp chức năng nhà máy $ get . Angular gọi $ get () để tạo đối tượng dịch vụ. Cú pháp của nhà cung cấp có thêm lợi thế là cấu hình đối tượng dịch vụ trước khi được khởi tạo. serviceInstance = $ get ();



63

Nhà máy

Bạn cung cấp cho AngularJS một chức năng, AngularJS sẽ lưu trữ và chèn giá trị trả về khi nhà máy được yêu cầu.

Thí dụ:

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

Sử dụng:

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

Dịch vụ

Bạn cung cấp cho AngularJS một chức năng, AngularJS sẽ gọi mới để khởi tạo nó. Đó là ví dụ mà AngularJS tạo ra sẽ được lưu trữ và chèn vào khi dịch vụ được yêu cầu. Vì mới được sử dụng để khởi tạo dịch vụ, từ khóa này là hợp lệ và đề cập đến thể hiện.

Thí dụ:

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

Sử dụng:

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

Các nhà cung cấp

Bạn cung cấp cho AngularJS một chức năng và AngularJS sẽ gọi $getchức năng của nó . Đó là giá trị trả về từ $gethàm sẽ được lưu trữ và được chèn khi dịch vụ được yêu cầu.

Các nhà cung cấp cho phép bạn định cấu hình nhà cung cấp trước khi AngularJS gọi $getphương thức để có được tiêm.

Thí dụ:

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

Cách sử dụng (dưới dạng tiêm trong bộ điều khiển)

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

Cách sử dụng (cấu hình nhà cung cấp trước $getđược gọi để tạo ra tiêm)

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

56

Tôi nhận thấy một điều thú vị khi chơi xung quanh với các nhà cung cấp.

Tầm nhìn của thuốc tiêm là khác nhau đối với các nhà cung cấp so với các dịch vụ và nhà máy. Nếu bạn khai báo "hằng số" AngularJS (ví dụ myApp.constant('a', 'Robert');:), bạn có thể đưa nó vào các dịch vụ, nhà máy và nhà cung cấp.

Nhưng nếu bạn khai báo "giá trị" AngularJS (ví dụ., myApp.value('b', {name: 'Jones'});), Bạn có thể đưa nó vào các dịch vụ và nhà máy, nhưng KHÔNG vào chức năng tạo nhà cung cấp. Tuy nhiên, bạn có thể đưa nó vào $getchức năng mà bạn xác định cho nhà cung cấp của mình. Điều này được đề cập trong tài liệu AngularJS, nhưng nó rất dễ bỏ lỡ. Bạn có thể tìm thấy nó trên trang% cung cấp trong các phần về các phương thức giá trị và hằng số.

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

Đây là một phần rất khó hiểu đối với người mới và tôi đã cố gắng làm rõ nó bằng những từ dễ dàng

AngularJS Service: được sử dụng để chia sẻ các chức năng tiện ích với tham chiếu dịch vụ trong bộ điều khiển. Dịch vụ là bản chất đơn lẻ vì vậy đối với một dịch vụ chỉ có một phiên bản được tạo trong trình duyệt và cùng một tham chiếu được sử dụng trên toàn trang.

Trong dịch vụ, chúng ta tạo các tên hàm làm thuộc tính với đối tượng này .

AngularJS Factory: mục đích của Factory cũng giống như Service, tuy nhiên trong trường hợp này chúng tôi tạo một đối tượng mới và thêm các hàm làm thuộc tính của đối tượng này và cuối cùng chúng tôi trả lại đối tượng này.

Nhà cung cấp AngularJS: mục đích của việc này lại giống nhau tuy nhiên Nhà cung cấp đưa ra đầu ra của hàm $ get.

Xác định và sử dụng Dịch vụ, Nhà máy và Nhà cung cấp được giải thích tại http://www.dotnetfunda.com/articles/show/3156/difference-b between-angularjs-service-fact-and-proider


2
Nhà máy và nhà cung cấp cũng là đối tượng đơn lẻ? Bất kỳ scanrio nơi các nhà máy được khuyến nghị trên các dịch vụ?
Sunil Garg

34

Đối với tôi cách tốt nhất và đơn giản nhất để hiểu sự khác biệt là:

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

Cách AngularJS khởi tạo các thành phần cụ thể (đơn giản hóa):

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

// factory
var angularFactory = factory(injection);

Vì vậy, đối với dịch vụ, thành phần AngularJS trở thành đối tượng của lớp được đại diện bởi hàm khai báo dịch vụ. Đối với nhà máy, đó là kết quả trả về từ chức năng khai báo của nhà máy. Nhà máy có thể hoạt động giống như dịch vụ:

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

Cách suy nghĩ đơn giản nhất là cách sau:

  • Dịch vụ là một ví dụ đối tượng singleton. Sử dụng các dịch vụ nếu bạn muốn cung cấp một đối tượng singleton cho mã của mình.
  • Nhà máy là một lớp học. Sử dụng các nhà máy nếu bạn muốn cung cấp các lớp tùy chỉnh cho mã của mình (không thể thực hiện được với các dịch vụ vì chúng đã được khởi tạo).

Ví dụ về 'lớp' của nhà máy được cung cấp trong các ý kiến ​​xung quanh, cũng như sự khác biệt của nhà cung cấp.


làm thế nào một dịch vụ có thể là một singleton nếu nó được khởi tạo mỗi khi nó được sử dụng? tôi có thể quay đầu lại ...
joe

Dịch vụ chỉ được khởi tạo một lần trong quá trình giải quyết phụ thuộc và sau đó khi bạn yêu cầu dịch vụ từ người tiêm, bạn luôn nhận được cùng một ví dụ. Có thể dễ dàng kiểm tra tại đây: jsfiddle.net/l0co/sovtu55t/1 , vui lòng chạy nó với bàn điều khiển. Bảng điều khiển cho thấy dịch vụ chỉ được khởi tạo một lần.
Lukasz Frankowski

oh tôi hiểu rồi tôi đã mong đợi có thể theo nghĩa đen new MyService()hoặc một cái gì đó :)
joe

33

Làm rõ của tôi về vấn đề này:

Về cơ bản, tất cả các loại được đề cập (dịch vụ, nhà máy, nhà cung cấp, v.v.) chỉ đang tạo và định cấu hình các biến toàn cục (tất nhiên là toàn cầu cho toàn bộ ứng dụng), giống như các biến toàn cầu kiểu cũ.

Mặc dù các biến toàn cục không được khuyến nghị, việc sử dụng thực sự của các biến toàn cục này là để cung cấp nội xạ phụ thuộc , bằng cách chuyển biến cho bộ điều khiển có liên quan.

Có nhiều mức độ phức tạp trong việc tạo các giá trị cho "biến toàn cục":

  1. Hằng số
    Điều này xác định một hằng số thực tế không nên được sửa đổi trong toàn bộ ứng dụng, giống như các hằng số trong các ngôn ngữ khác là (thứ mà JavaScript thiếu).
  2. Giá trị
    Đây là một giá trị hoặc đối tượng có thể sửa đổi và nó đóng vai trò là một biến toàn cục, thậm chí có thể được đưa vào khi tạo các dịch vụ hoặc nhà máy khác (xem thêm về những điều này). Tuy nhiên, nó phải là " giá trị theo nghĩa đen ", có nghĩa là người ta phải viết ra giá trị thực và không thể sử dụng bất kỳ logic tính toán hoặc lập trình nào (nói cách khác 39 hoặc myText hoặc {prop: "value"} đều ổn, nhưng 2 +2 thì không).
  3. Nhà máy
    Một giá trị tổng quát hơn, có thể được tính toán ngay lập tức. Nó hoạt động bằng cách chuyển một hàm cho AngularJS với logic cần thiết để tính giá trị và AngularJS thực thi nó, và nó lưu giá trị trả về trong biến đã đặt tên.
    Lưu ý rằng có thể trả về một đối tượng (trong trường hợp đó nó sẽ hoạt động tương tự như một dịch vụ ) hoặc một hàm (sẽ được lưu trong biến dưới dạng hàm gọi lại).
  4. Dịch vụ
    Một dịch vụ là phiên bản rút gọn hơn của nhà máy , chỉ hợp lệ khi giá trị là một đối tượng và nó cho phép ghi bất kỳ logic nào trực tiếp vào hàm (như thể nó sẽ là một hàm tạo), cũng như khai báo và truy cập các thuộc tính đối tượng sử dụng từ khóa này .
  5. Nhà cung cấp
    Không giống như dịch vụ là phiên bản đơn giản của nhà máy , nhà cung cấp là cách khởi tạo các biến "toàn cầu" phức tạp hơn nhưng linh hoạt hơn, với tính linh hoạt lớn nhất là tùy chọn đặt giá trị từ app.config.
    Nó hoạt động giống như sử dụng kết hợp dịch vụnhà cung cấp , bằng cách chuyển cho nhà cung cấp một hàm có các thuộc tính được khai báo bằng từ khóa này , có thể được sử dụng từ app.config.
    Sau đó, nó cần phải có một hàm $ .get riêng được thực thi bởi AngularJS sau khi đặt các thuộc tính trên thông qua app.configtệp và hàm $ .get này hoạt động giống như nhà máy ở trên, trong đó giá trị trả về của nó được sử dụng để khởi tạo các biến "toàn cầu".

26

Hiểu biết của tôi rất đơn giản dưới đây.

Factory: Bạn chỉ cần tạo một đối tượng bên trong nhà máy và trả lại nó.

Dịch vụ:

Bạn chỉ có một hàm tiêu chuẩn sử dụng từ khóa này để xác định hàm.

Các nhà cung cấp:

Có một $getđối tượng mà bạn xác định và nó có thể được sử dụng để lấy đối tượng trả về dữ liệu.


Không phải bạn đã trộn lẫn Nhà máy và Dịch vụ sao? Dịch vụ tạo ra nơi nhà máy trở lại.
Flavien Volken

Khi bạn khai báo tên dịch vụ dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp một thể hiện của hàm. Nói cách khác, FunctionYouPassedToService () mới. Đối tượng đối tượng này trở thành đối tượng dịch vụ mà AngularJS đăng ký và tiêm sau này cho các dịch vụ / bộ điều khiển khác nếu cần. // nhà máy Khi bạn khai báo tên máy là một đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi tham chiếu hàm được truyền cho module.factory.
sajan

Được rồi, vì vậy, góc cạnh của nhà máy là một đơn vị trong đó "dịch vụ" thực sự là một nhà máy (theo thuật ngữ mẫu thiết kế chung)
Flavien Volken

25

Tóm tắt từ các tài liệu Angular :

  • Có năm loại công thức xác định cách tạo đối tượng: Giá trị , Nhà máy , Dịch vụ , Nhà cung cấpHằng số .
  • Nhà máyDịch vụ là những công thức được sử dụng phổ biến nhất. Sự khác biệt duy nhất giữa chúng là công thức Dịch vụ hoạt động tốt hơn cho các đối tượng thuộc loại tùy chỉnh, trong khi Nhà máy có thể tạo ra các hàm và hàm nguyên gốc JavaScript.
  • Công thức nhà cung cấp là loại công thức cốt lõi và tất cả những công thức khác chỉ là đường cú pháp trên đó.
  • Nhà cung cấp là loại công thức phức tạp nhất. Bạn không cần nó trừ khi bạn đang xây dựng một đoạn mã có thể tái sử dụng cần cấu hình toàn cầu.

nhập mô tả hình ảnh ở đây


Câu trả lời hay nhất từ ​​SO:

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


20

Tất cả các câu trả lời tốt rồi. Tôi muốn thêm vài điểm nữa về Dịch vụNhà máy . Cùng với sự khác biệt giữa dịch vụ / nhà máy. Và người ta cũng có thể có những câu hỏi như:

  1. Tôi nên sử dụng dịch vụ hoặc nhà máy? Có gì khác biệt?
  2. Họ làm giống nhau hay có hành vi giống nhau?

Hãy bắt đầu với sự khác biệt giữa Dịch vụ và nhà máy:

  1. Cả hai đều là Singletons : Bất cứ khi nào Angular lần đầu tiên tìm thấy chúng như một sự phụ thuộc, nó sẽ tạo ra một thể hiện duy nhất của dịch vụ / nhà máy. Khi cá thể được tạo, cùng một thể hiện được sử dụng mãi mãi.

  2. Có thể được sử dụng để mô hình hóa một đối tượng với hành vi : Cả hai đều có thể có các phương thức, các biến trạng thái bên trong, v.v. Mặc dù cách bạn viết mã đó sẽ khác nhau.

Dịch vụ:

Một dịch vụ là một hàm tạo, và Angular sẽ khởi tạo nó bằng cách gọi mới yourServiceName(). Điều này có nghĩa là một vài điều.

  1. Hàm và biến đối tượng sẽ là thuộc tính của this.
  2. Bạn không cần phải trả lại một giá trị. Khi Angular gọi new yourServiceName(), nó sẽ nhận được thisđối tượng với tất cả các thuộc tính bạn đặt trên nó.

Ví dụ mẫu:

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

Khi Angular đưa MyServicedịch vụ này vào một bộ điều khiển phụ thuộc vào nó, bộ điều khiển đó sẽ nhận được một MyServicechức năng mà nó có thể gọi các hàm trên, ví dụ MyService.aServiceMethod ().

Hãy cẩn thận vớithis :

Vì dịch vụ được xây dựng là một đối tượng, nên các phương thức bên trong nó có thể tham chiếu đến điều này khi chúng được gọi:

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.setScoreChẳng hạn, bạn có thể muốn gọi một chuỗi lời hứa, nếu bạn đã khởi tạo điểm số bằng cách lấy nó từ máy chủ: $http.get('/score').then(ScoreKeeper.setScore).Vấn đề với điều này là ScoreKeeper.setScoresẽ thisbị ràng buộc nullvà bạn sẽ gặp lỗi. Cách tốt hơn sẽ là $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Cho dù bạn có chọn sử dụng điều này trong phương thức dịch vụ của mình hay không, hãy cẩn thận với cách bạn gọi chúng.

Trả lại một giá trị từ mộtService :

Do cách các hàm tạo JavaScript hoạt động, nếu bạn trả về một giá trị phức tạp (i.e., an Object)từ một constructorhàm, người gọi sẽ nhận được Đối tượng đó thay vì thể hiện này.

Điều này có nghĩa là về cơ bản bạn có thể sao chép-dán ví dụ về nhà máy từ bên dưới, thay thế factorybằng servicevà nó sẽ hoạt động:

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

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

Vì vậy, khi Angular xây dựng dịch vụ của bạn với MyService () mới, nó sẽ nhận được đối tượng api đó thay vì đối tượng MyService.

Đây là hành vi cho bất kỳ giá trị phức tạp (đối tượng, hàm) nhưng không dành cho các kiểu nguyên thủy.

Các nhà máy:

Một nhà máy là một hàm cũ đơn giản trả về một giá trị. Giá trị trả lại là những gì được đưa vào những thứ phụ thuộc vào nhà máy. Một mô hình nhà máy điển hình trong Angular là trả về một đối tượng có chức năng là các thuộc tính, như thế này:

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

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

  return api;
});

Giá trị được tiêm cho một phụ thuộc của nhà máy là giá trị trả về của nhà máy và nó không phải là một đối tượng. Nó có thể là một chức năng

Câu trả lời cho 1 và 2 câu hỏi trên:

Đối với hầu hết các phần, chỉ cần gắn bó với việc sử dụng các nhà máy cho tất cả mọi thứ. Hành vi của họ dễ hiểu hơn. Không có lựa chọn nào về việc có nên trả lại giá trị hay không, và hơn nữa, không có lỗi nào được đưa ra nếu bạn làm sai.

Mặc dù vậy, tôi vẫn gọi chúng là dịch vụ của người Hồi giáo khi tôi nói về việc tiêm chúng như là phụ thuộc.

Hành vi dịch vụ / nhà máy rất giống nhau và một số người sẽ nói rằng một trong hai là tốt. Điều đó hơi đúng, nhưng tôi thấy dễ dàng hơn khi làm theo lời khuyên của hướng dẫn phong cách của John Papa và chỉ cần gắn bó với các nhà máy. **


16

Một sự làm rõ bổ sung là các nhà máy có thể tạo ra các chức năng / nguyên thủy, trong khi các dịch vụ thì không thể. Hãy xem jsFiddle này dựa trên Epokk's: http://jsfiddle.net/skeller88/PxdSP/1351/ .

Nhà máy trả về một hàm có thể được gọi:

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

Nhà máy cũng có thể trả về một đối tượng bằng một phương thức có thể được gọi:

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

Dịch vụ trả về một đối tượng với một phương thức có thể được gọi:

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

Để biết thêm chi tiết, hãy xem bài đăng tôi đã viết về sự khác biệt: http://www.shanemkeller.com/tldr-service-vs-factories-in-angular/


16

Đã có câu trả lời tốt, nhưng tôi chỉ muốn chia sẻ câu hỏi này.

Trước hết: Nhà cung cấp là cách / công thức để tạo ra một service(đối tượng singleton) giả sử được tiêm bởi $ kim phun (cách AngulaJS đi về mô hình IoC).

Giá trị, Nhà máy, Dịch vụ và Hằng số (4 cách) - đường cú pháp trên cách cung cấp / recepie của Nhà cung cấp .

Service vs Factorymột phần đã được bảo hiểm: https://www.youtube.com/watch?v=BLzNCkPn3ao

Dịch vụ là tất cả về newtừ khóa mà như chúng ta biết có 4 điều:

  1. tạo đối tượng hoàn toàn mới
  2. liên kết nó với prototypeđối tượng của nó
  3. kết nối contextvớithis
  4. và trả lại this

Factory là tất cả về Mô hình nhà máy - chứa các hàm trả về các Đối tượng như Dịch vụ đó.

  1. khả năng sử dụng các dịch vụ khác (có sự phụ thuộc)
  2. khởi tạo dịch vụ
  3. trì hoãn / lười khởi tạo

Và video đơn giản / ngắn này: bao gồm cả Nhà cung cấp : https://www.youtube.com/watch?v=HvTZbQ_hUZY (ở đó bạn thấy có thể thấy cách họ đi từ nhà máy đến nhà cung cấp)

Công thức của nhà cung cấp được sử dụng chủ yếu trong cấu hình ứng dụng, trước khi ứng dụng hoàn toàn khởi động / khởi tạo.


14

Sau khi đọc tất cả các bài đăng này Nó tạo ra nhiều nhầm lẫn cho tôi .. Nhưng tất cả vẫn là thông tin đáng giá .. cuối cùng tôi đã tìm thấy bảng sau đây sẽ cung cấp thông tin với sự so sánh đơn giản

  • Người tiêm sử dụng công thức nấu ăn để tạo ra hai loại đối tượng: dịch vụ và đối tượng mục đích đặc biệt
  • Có năm loại công thức xác định cách tạo đối tượng: Giá trị, Nhà máy, Dịch vụ, Nhà cung cấp và Hằng số.
  • Nhà máy và Dịch vụ là những công thức được sử dụng phổ biến nhất. Sự khác biệt duy nhất giữa chúng là công thức Dịch vụ hoạt động tốt hơn cho các đối tượng thuộc loại tùy chỉnh, trong khi Nhà máy có thể tạo ra các hàm và hàm nguyên gốc JavaScript.
  • Công thức nhà cung cấp là loại công thức cốt lõi và tất cả những công thức khác chỉ là đường cú pháp trên đó.
  • Nhà cung cấp là loại công thức phức tạp nhất. Bạn không cần nó trừ khi bạn đang xây dựng một đoạn mã có thể tái sử dụng cần cấu hình toàn cầu.
  • Tất cả các đối tượng mục đích đặc biệt ngoại trừ Bộ điều khiển được xác định thông qua các công thức nấu ăn của Nhà máy.

nhập mô tả hình ảnh ở đây

Và cho người mới bắt đầu hiểu: - Điều này có thể không đúng trường hợp sử dụng nhưng ở cấp độ cao đây là những gì usecase cho ba.

  1. Nếu bạn muốn sử dụng trong chức năng cấu hình mô-đun góc, nên tạo như nhà cung cấp

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

  1. Cuộc gọi Ajax hoặc tích hợp bên thứ ba cần phải là dịch vụ .
  2. Đối với các thao tác dữ liệu, hãy tạo nó làm nhà máy

Đối với các kịch bản cơ bản, nhà máy và dịch vụ hoạt động như nhau.


13

Dưới đây là một số mã trình biên dịch mà tôi đã đưa ra dưới dạng mẫu mã cho nhà máy đối tượng trong AngularjS. Tôi đã sử dụng Car / CarFactory làm ví dụ để minh họa. Làm cho mã thực hiện đơn giản trong bộ điều khiển.

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

Đây là một ví dụ đơn giản hơn. Tôi đang sử dụng một vài thư viện bên thứ ba mong muốn một đối tượng "Vị trí" phơi bày vĩ độ và kinh độ, nhưng thông qua các thuộc tính đối tượng khác nhau. Tôi không muốn hack mã nhà cung cấp, vì vậy tôi đã điều chỉnh các đối tượng "Vị trí" mà tôi đang đi qua.

    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

Sử dụng làm tài liệu tham khảo trang này và tài liệu (dường như đã được cải thiện rất nhiều kể từ lần cuối tôi xem), tôi đã kết hợp bản demo thế giới thực (-ish) sau đây sử dụng 4 trong 5 hương vị của nhà cung cấp; Giá trị, liên tục, nhà máy và nhà cung cấp đầy đủ thổi.

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>

ứng dụng

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

Bản demo làm việc .


12

Câu trả lời này giải quyết chủ đề / câu hỏi

Làm thế nào Nhà máy, Dịch vụ và Hằng số - chỉ là đường cú pháp trên đầu công thức của nhà cung cấp?

HOẶC LÀ

Làm thế nào nhà máy, dịch vụ và nhà cung cấp là simailar trong nội bộ

về cơ bản những gì xảy ra là

Khi bạn tạo một factory()bộ, bạn functionđã cung cấp trong đối số thứ hai cho nhà cung cấp $getvà trả lại ( provider(name, {$get:factoryFn })), tất cả những gì bạn nhận được làprovider nhưng không có thuộc tính / phương thức nào khác ngoài$get điều đó provider(có nghĩa là bạn không thể định cấu hình này)

Mã nguồn của nhà máy

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

Khi thực hiện service()trả lại, bạn cung cấp cho nhà máy () mộtfunction tiêm constructor(trả lại thể hiện của hàm tạo mà bạn đã cung cấp trong dịch vụ của mình) và trả về

Mã nguồn của dịch vụ

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

Vì vậy, về cơ bản trong cả hai trường hợp, cuối cùng bạn sẽ nhận được một nhà cung cấp $ get set cho chức năng của bạn mà bạn đã cung cấp, nhưng bạn có thể cung cấp bất cứ thứ gì ngoài $ get như ban đầu bạn có thể cung cấp trong nhà cung cấp () cho khối cấu hình


11

Tôi biết rất nhiều câu trả lời xuất sắc nhưng tôi phải chia sẻ kinh nghiệm sử dụng
1. servicetrong hầu hết các trường hợp mặc định
2. factoryđược sử dụng để tạo ra dịch vụ cụ thể đó

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

và sử dụng:

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

Ít đến bữa tiệc. Nhưng tôi nghĩ rằng điều này hữu ích hơn cho những ai muốn tìm hiểu (hoặc có sự rõ ràng) về việc phát triển Dịch vụ tùy chỉnh Angular JS bằng cách sử dụng các phương pháp của nhà máy, dịch vụ và nhà cung cấp.

Tôi đã xem qua video này giải thích rõ ràng về các phương pháp của nhà máy, dịch vụ và nhà cung cấp để phát triển Dịch vụ tùy chỉnh AngularJS:

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

Mã nguồn: http://www.techcbt.com/Post3533/Angular-JS-basics/how-to-develop-angularjs-custom-service

Mã được đăng ở đây được sao chép trực tiếp từ nguồn trên, để mang lại lợi ích cho độc giả.

Mã cho dịch vụ tùy chỉnh dựa trên "nhà máy" như sau (đi kèm với cả phiên bản đồng bộ hóa và không đồng bộ cùng với gọi dịch vụ 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;
  }
]);

Mã cho phương pháp "dịch vụ" cho Dịch vụ tùy chỉnh (điều này khá giống với 'nhà máy', nhưng khác với quan điểm cú pháp):

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

}]);

Mã cho phương pháp "nhà cung cấp" cho Dịch vụ tùy chỉnh (điều này là cần thiết, nếu bạn muốn phát triển dịch vụ có thể được định cấu hình):

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

Cuối cùng, UI hoạt động với bất kỳ dịch vụ nào ở trên:

<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

Chỉ cần làm rõ mọi thứ, từ nguồn AngularJS, bạn có thể thấy một dịch vụ chỉ cần gọi chức năng của nhà máy mà lần lượt gọi chức năng của nhà cung cấp:

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

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

9

Chúng ta hãy thảo luận về ba cách xử lý logic kinh doanh trong AngularJS một cách đơn giản: ( Lấy cảm hứng từ khóa học Coursera AngularJS của Yaakov )

DỊCH VỤ :

Cú pháp:

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>

Các tính năng của dịch vụ:

  1. Lazily Instantiated : Nếu nó không được tiêm, nó sẽ không được khởi tạo bao giờ. Vì vậy, để sử dụng nó sẽ phải tiêm nó vào một mô-đun.
  2. Singleton : Nếu được thêm vào nhiều mô-đun, tất cả sẽ chỉ có quyền truy cập vào một trường hợp cụ thể. Đó là lý do tại sao rất thuận tiện để chia sẻ dữ liệu trên các bộ điều khiển khác nhau.

NHÀ MÁY

Trước tiên, hãy xem cú pháp:

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

Bây giờ sử dụng hai ở trên trong bộ điều khiển:

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

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

Đặc điểm của Nhà máy:

  1. Theo mô hình thiết kế nhà máy. Nhà máy là một nơi trung tâm sản xuất các đối tượng hoặc chức năng mới.
  2. Không chỉ sản xuất singleton, mà các dịch vụ tùy biến.
  3. Các .service()phương pháp là một nhà máy mà luôn tạo ra cùng một loại dịch vụ, mà là một singleton, và không có cách nào dễ dàng để cấu hình hành vi của nó. .service()Phương pháp đó thường được sử dụng như một lối tắt cho một cái gì đó không yêu cầu bất kỳ cấu hình nào.

CÁC NHÀ CUNG CẤP

Trước tiên chúng ta hãy xem Cú pháp trước:

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

}

Các tính năng của Nhà cung cấp:

  1. Nhà cung cấp là phương pháp linh hoạt nhất để tạo ra các dịch vụ trong Angular.
  2. Không chỉ chúng tôi có thể tạo một nhà máy có thể cấu hình động, mà tại thời điểm sử dụng nhà máy, với phương thức của nhà cung cấp, chúng tôi có thể tùy chỉnh cấu hình nhà máy chỉ một lần khi khởi động toàn bộ ứng dụng của chúng tôi.
  3. Nhà máy sau đó có thể được sử dụng trong suốt ứng dụng với các cài đặt tùy chỉnh. Nói cách khác, chúng ta có thể cấu hình nhà máy này trước khi ứng dụng bắt đầu. Trong thực tế trong tài liệu góc, người ta đã đề cập rằng phương thức của nhà cung cấp là những gì thực sự được thực hiện phía sau hậu trường khi chúng ta định cấu hình các dịch vụ của mình bằng .servicehoặc.factory phương pháp.
  4. Đây $getlà một chức năng được gắn trực tiếp với thể hiện của nhà cung cấp. Chức năng đó là chức năng của nhà máy . Nói cách khác, nó giống như cái mà chúng ta sử dụng để cung cấp cho .factoryphương thức. Trong chức năng đó, chúng tôi tạo ra dịch vụ riêng của chúng tôi. Đây $getbất động sản, đó là một chức năng, là những gì làm cho các nhà cung cấp một nhà cung cấp . AngularJS hy vọng nhà cung cấp sẽ có một tài sản $ get có giá trị là một chức năng mà Angular sẽ coi là một chức năng của nhà máy. Nhưng điều làm cho toàn bộ nhà cung cấp này thiết lập rất đặc biệt, đó là thực tế là chúng tôi có thể cung cấp một số configđối tượng bên trong nhà cung cấp dịch vụ và thường đi kèm với các mặc định mà sau này chúng tôi có thể ghi đè lên trong bước, nơi chúng tôi có thể định cấu hình toàn bộ ứng dụng.

7

Nhà máy: Nhà máy bạn thực sự tạo ra một đối tượng bên trong nhà máy và trả lại.
dịch vụ: Dịch vụ bạn chỉ có một chức năng tiêu chuẩn sử dụng từ khóa này để xác định chức năng.
nhà cung cấp: Nhà cung cấp có $ giúp bạn xác định và nó có thể được sử dụng để lấy đối tượng trả về dữ liệu.


7

Về cơ bản, Nhà cung cấp, Nhà máy và Dịch vụ đều là Dịch vụ. Nhà máy là trường hợp đặc biệt của Dịch vụ khi tất cả những gì bạn cần là hàm $ get (), cho phép bạn viết nó với ít mã hơn.

Sự khác biệt chính giữa Dịch vụ, Nhà máy và Nhà cung cấp là sự phức tạp của chúng. Dịch vụ là hình thức đơn giản nhất, Các nhà máy mạnh hơn một chút và Nhà cung cấp có thể định cấu hình khi chạy.

Dưới đây là tóm tắt về thời điểm sử dụng từng:

Nhà máy : Giá trị bạn đang cung cấp cần được tính toán dựa trên dữ liệu khác.

Dịch vụ : Bạn đang trả về một đối tượng với các phương thức.

Nhà cung cấp : Bạn muốn có thể định cấu hình, trong giai đoạn cấu hình, đối tượng sẽ được tạo trước khi nó được tạo. Sử dụng Nhà cung cấp chủ yếu trong cấu hình ứng dụng, trước khi ứng dụng được khởi tạo hoàn toàn.


erm. Giá trị, Nhà máy, Dịch vụ và Hằng số - chỉ là đường cú pháp trên đầu công thức của nhà cung cấp. Angularjs docs - nhà cung cấp
Sudarshan_SMD

vâng tôi đồng ý, bây giờ với góc 4, chúng tôi không còn đau đầu nữa
eGhoul

4

1. Dịch vụ là các đối tượng đơn lẻ được tạo khi cần thiết và không bao giờ được dọn sạch cho đến khi kết thúc vòng đời ứng dụng (khi đóng trình duyệt). Bộ điều khiển bị phá hủy và dọn dẹp khi không còn cần thiết.

2. Cách dễ nhất để tạo một dịch vụ là sử dụng phương thức Factory (). Phương thức Factory () cho phép chúng ta xác định một dịch vụ bằng cách trả về một đối tượng có chứa các hàm dịch vụ và dữ liệu dịch vụ. Hàm định nghĩa dịch vụ là nơi chúng tôi đặt các dịch vụ có thể tiêm của mình, chẳng hạn như $ http và $ q. Ví dụ:

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

Sử dụng nhà máy () trong ứng dụng của chúng tôi

Thật dễ dàng để sử dụng nhà máy trong ứng dụng của chúng tôi vì chúng tôi có thể chỉ cần đưa nó vào nơi chúng tôi cần vào thời gian chạy.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Mặt khác, phương thức service () cho phép chúng ta tạo một dịch vụ bằng cách định nghĩa hàm xây dựng. Chúng tôi có thể sử dụng một đối tượng nguyên mẫu để xác định dịch vụ của mình, thay vì một đối tượng javascript thô. Tương tự như phương thức Factory (), chúng ta cũng sẽ đặt các hàm tiêm trong định nghĩa hàm.
  2. Cách mức thấp nhất để tạo một dịch vụ là sử dụng phương thức cung cấp (). Đây là cách duy nhất để tạo một dịch vụ mà chúng ta có thể định cấu hình bằng hàm .config (). Không giống như các phương thức trước đây, chúng ta sẽ đặt các hàm tiêm theo định nghĩa hàm $ get () được định nghĩa này.

-3

Đường tổng hợp là sự khác biệt . Chỉ có nhà cung cấp là cần thiết. Hay nói cách khác, chỉ có nhà cung cấp là góc cạnh thực sự, tất cả những người khác đều có nguồn gốc (để giảm mã). Cũng có một phiên bản đơn giản, được gọi là Value () chỉ trả về giá trị, không tính toán hoặc hàm. Ngay cả Giá trị có nguồn gốc từ nhà cung cấp!

Vậy tại sao lại phức tạp như vậy, tại sao chúng ta không thể sử dụng nhà cung cấp và quên mọi thứ khác? Nó được cho là giúp chúng ta viết mã dễ dàng và giao tiếp tốt hơn. Và câu trả lời trực tiếp sẽ là, càng phức tạp thì càng bán được một khung tốt hơn.


  • Nhà cung cấp có thể trả về giá trị = Giá trị
  • Nhà cung cấp có thể khởi tạo và trả về = Nhà máy (+ Giá trị)
  • Nhà cung cấp có thể khởi tạo + làm một cái gì đó = Dịch vụ (+ Nhà máy, + Giá trị)
  • Nhà cung cấp = phải chứa một thuộc tính được gọi là $ get (+ Nhà máy, + Dịch vụ, + Giá trị)

Tiêm góc cho chúng ta gợi ý đầu tiên để đi đến kết luận này.

"$ Kim phun được sử dụng để truy xuất các thể hiện đối tượng như được xác định bởi nhà cung cấp " không phải dịch vụ, không phải nhà máy mà là nhà cung cấp.

Và một câu trả lời tốt hơn sẽ là: "Một dịch vụ Angular được tạo ra bởi một nhà máy dịch vụ. Các nhà máy dịch vụ này là các chức năng, do đó, được tạo ra bởi một nhà cung cấp dịch vụ. Các nhà cung cấp dịch vụ là các hàm xây dựng. được gọi là $ get, giữ chức năng nhà máy dịch vụ. "

Vì vậy, nhà cung cấp chính và người tiêm và tất cả sẽ rơi vào vị trí :). Và nó trở nên thú vị trong Typecript khi $ get có thể được triển khai trong một nhà cung cấp bằng cách kế thừa từ IServiceProvider.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.