AngularJS: Layanan vs penyedia vs pabrik


3320

Apa perbedaan antara a Service, Providerdan Factorydalam AngularJS?


244
Saya menemukan bahwa semua istilah Angular mengintimidasi untuk pemula. Kami mulai dengan lembar contekan ini yang sedikit lebih mudah dipahami oleh programmer kami sambil mempelajari Angular demisx.github.io/angularjs/2014/09/14/… . Semoga ini bisa membantu tim Anda juga.
demisx

7
Menurut pendapat saya, cara terbaik untuk memahami perbedaannya adalah dengan menggunakan dokumentasi Angular sendiri: docs.angularjs.org/guide/providers dijelaskan dengan sangat baik dan menggunakan contoh khusus untuk membantu Anda memahaminya.
Rafael Merlin

3
@Blaise Terima kasih! Per komentar saya dalam posting ini, saya sengaja meninggalkannya, karena 99% kasus penggunaan dari pengalaman saya dapat ditangani dengan sukses service.factory. Tidak ingin memperumit masalah ini lebih lanjut.
demisx

3
Saya menemukan diskusi ini juga sangat berguna stackoverflow.com/questions/18939709/…
Anand Gupta

3
Berikut adalah beberapa jawaban yang bagus tentang bagaimanaservices,factoriesdanprovidersbekerja.
Mistalis

Jawaban:


2866

Dari milis AngularJS saya mendapat utas luar biasa yang menjelaskan layanan vs pabrik vs penyedia dan penggunaan injeksi mereka. Kompilasi jawaban:

Jasa

Sintaks: module.service( 'serviceName', function );
Hasil: Saat mendeklarasikan serviceName sebagai argumen yang dapat diinjeksi, Anda akan diberikan instance dari fungsi tersebut. Dengan kata lain new FunctionYouPassedToService() .

Pabrik

Sintaks: module.factory( 'factoryName', function );
Hasil: Ketika mendeklarasikan factoryName sebagai argumen injeksi, Anda akan diberikan nilai yang dikembalikan dengan memohon referensi fungsi yang diteruskan ke module.factory .

Penyedia

Sintaks: module.provider( 'providerName', function );
Hasil: Saat mendeklarasikan providerName sebagai argumen yang dapat diinjeksi, Anda akan diberikan (new ProviderFunction()).$get() . Fungsi konstruktor adalah instantiated sebelum metode $ get dipanggil - ProviderFunctionadalah referensi fungsi yang diteruskan ke module.provider.

Penyedia memiliki keuntungan bahwa mereka dapat dikonfigurasi selama fase konfigurasi modul.

Lihat di sini untuk kode yang disediakan.

Berikut ini penjelasan lebih lanjut dari Misko:

provide.value('a', 123);

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

Dalam hal ini injektor hanya mengembalikan nilai apa adanya. Tetapi bagaimana jika Anda ingin menghitung nilainya? Kemudian gunakan pabrik

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

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

Begitu factory adalah fungsi yang bertanggung jawab untuk menciptakan nilai. Perhatikan bahwa fungsi pabrik dapat meminta dependensi lainnya.

Tetapi bagaimana jika Anda ingin menjadi lebih OO dan memiliki kelas yang disebut Greeter?

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

Maka untuk instantiate Anda harus menulis

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

Lalu kita bisa meminta 'penyapa' di controller seperti ini

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

Tapi itu terlalu bertele-tele. Cara yang lebih singkat untuk menulis ini adalahprovider.service('greeter', Greeter);

Tetapi bagaimana jika kita ingin mengkonfigurasi Greeterkelas sebelum injeksi? Lalu kita bisa menulis

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

Maka kita bisa melakukan ini:

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

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

Sebagai catatan, service, factory, dan valuesemuanya berasal dari penyedia.

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
Lihat juga stackoverflow.com/a/13763886/215945 yang membahas perbedaan antara layanan dan pabrik.
Mark Rajcok

3
Dalam edit 611 saya menambahkan penggunaan konstanta dan nilai sudut. Untuk menunjukkan perbedaan yang lain sudah ditunjukkan. jsbin.com/ohamub/611/edit
Nick

17
Meskipun suatu layanan dipanggil dengan membuat instance fungsi. Ini sebenarnya dibuat hanya sekali per injector yang membuatnya seperti singleton. docs.angularjs.org/guide/dev_guide.services.creating_services
angelokh

33
Contoh ini bisa luar biasa jika menggunakan contoh praktis yang jelas. Saya tersesat mencoba mencari tahu apa gunanya toEqualdan greeter.Greetapa. Mengapa tidak menggunakan sesuatu yang sedikit lebih nyata dan bisa dihubungkan?
Kyle Pennell

5
Menggunakan fungsi expect () adalah pilihan yang buruk untuk menjelaskan sesuatu. Gunakan kode dunia nyata lain kali.
Craig

812

Demo JS Fiddle

Contoh "Hello world" dengan 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
Tidak thismengubah konteks dalam $getfungsi? - Anda tidak lagi merujuk ke penyedia instantiated dalam fungsi itu.
Nate-Wilkins

12
@Nate: thissebenarnya tidak mengubah konteks, karena apa yang dipanggil adalah new Provider()$ get (), di mana Providerfungsi diteruskan app.provider. Maksudnya dikatakan $get()dipanggil sebagai metode pada konstruksi Provider, jadi thisakan merujuk Providerseperti contoh yang disarankan.
Brandon

1
@Brandon Ohh ok itu bagus kalau begitu. Sekilas membingungkan - terima kasih atas klarifikasi!
Nate-Wilkins

3
Mengapa saya dapatkan Unknown provider: helloWorldProvider <- helloWorldketika menjalankan ini secara lokal? Mengomentari itu, kesalahan yang sama untuk 2 contoh lainnya. Apakah ada konfigurasi penyedia tersembunyi? (Angular 1.0.8) - Ditemukan: stackoverflow.com/questions/12339272/…
Antoine

4
Adalah alasan mengapa @Antoine mendapatkan kesalahan "Tidak diketahui: helloWorldProvider" karena dalam kode .config Anda, Anda menggunakan 'helloWorldProvider', tetapi ketika Anda menentukan penyedia di myApp.provider ('helloWorld', function ()), Anda menggunakan 'Halo Dunia'? Dengan kata lain, dalam kode konfigurasi Anda, bagaimana sudut tahu Anda merujuk ke penyedia helloWorld? Terima kasih
jmtoung

645

TL; DR

1) Saat Anda menggunakan Pabrik, Anda membuat objek, menambahkan properti ke sana, lalu mengembalikan objek yang sama. Ketika Anda melewati pabrik ini ke controller Anda, properti-properti pada objek sekarang akan tersedia di controller melalui pabrik Anda.

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) Saat Anda menggunakan Layanan , AngularJS membuat instance di belakang layar dengan kata kunci 'baru'. Karena itu, Anda akan menambahkan properti ke 'ini' dan layanan akan mengembalikan 'ini'. Ketika Anda melewati layanan ke controller Anda, properti-properti di 'ini' sekarang akan tersedia pada controller itu melalui layanan Anda.

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

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



3) Penyedia adalah satu-satunya layanan yang dapat Anda gunakan untuk fungsi .config () Anda. Gunakan penyedia ketika Anda ingin memberikan konfigurasi modul-lebar untuk objek layanan Anda sebelum membuatnya tersedia.

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = This was set in config’;
});



Non TL; DR

1) Pabrik
Pabrik adalah cara paling populer untuk membuat dan mengonfigurasi layanan. Benar-benar tidak lebih dari apa yang dikatakan TL; DR. Anda cukup membuat objek, menambahkan properti ke sana, lalu mengembalikan objek yang sama. Kemudian ketika Anda melewati pabrik ke controller Anda, properti-properti pada objek sekarang akan tersedia di controller melalui pabrik Anda. Contoh yang lebih luas ada di bawah ini.

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

Sekarang properti apa pun yang kita lampirkan ke 'layanan' akan tersedia untuk kita ketika kita melewati 'myFactory' ke controller kita.

Sekarang mari kita tambahkan beberapa variabel 'pribadi' ke fungsi panggilan balik kita. Ini tidak akan dapat diakses langsung dari controller, tetapi kami akhirnya akan menyiapkan beberapa metode pengambil / penyetel pada 'layanan' untuk dapat mengubah variabel 'pribadi' ini ketika diperlukan.

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

Di sini Anda akan melihat kami tidak melampirkan variabel / fungsi itu ke 'layanan'. Kami hanya membuatnya untuk menggunakan atau memodifikasinya nanti.

  • baseUrl adalah URL dasar yang dibutuhkan oleh iTunes API
  • _artist adalah artis yang ingin kita cari
  • _finalUrl adalah URL final dan sepenuhnya dibangun yang kami akan membuat panggilan ke iTunes
  • makeUrl adalah fungsi yang akan membuat dan mengembalikan URL ramah iTunes kami.

Sekarang, ketika variabel pembantu dan fungsi dan fungsi kami sudah ada, mari kita tambahkan beberapa properti ke objek 'layanan'. Apa pun yang kita pakai pada 'layanan' dapat langsung digunakan di dalam pengontrol mana pun kita melewatkan 'myFactory'.

Kita akan membuat metode setArtist dan getArtist yang hanya mengembalikan atau mengatur artis. Kami juga akan membuat metode yang akan memanggil iTunes API dengan URL yang kami buat. Metode ini akan mengembalikan janji yang akan dipenuhi setelah data telah kembali dari iTunes API. Jika Anda belum memiliki banyak pengalaman menggunakan janji-janji di AngularJS, saya sangat merekomendasikan melakukan penyelaman mendalam pada mereka.

Di bawah setArtist menerima artis dan memungkinkan Anda untuk mengatur artis. getArtist mengembalikan artis. callItunes first calls makeUrl () untuk membangun URL yang akan kami gunakan dengan permintaan $ http kami. Kemudian ia membuat objek janji, membuat permintaan $ http dengan url akhir kami, lalu karena $ http mengembalikan janji, kami dapat memanggil .success atau .error setelah permintaan kami. Kami kemudian menyelesaikan janji kami dengan data iTunes, atau kami menolaknya dengan pesan yang mengatakan 'Ada kesalahan'.

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

Sekarang pabrik kami selesai. Kami sekarang dapat menyuntikkan 'myFactory' ke dalam pengontrol apa pun dan kami kemudian dapat memanggil metode kami yang kami lampirkan ke objek layanan kami (setArtist, getArtist, dan 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);
      })
  }
});

Pada controller di atas kami menyuntikkan layanan 'myFactory'. Kami kemudian mengatur properti pada objek $ scope kami dengan data dari 'myFactory'. Satu-satunya kode rumit di atas adalah jika Anda belum pernah berurusan dengan janji sebelumnya. Karena callItunes mengembalikan janji, kita dapat menggunakan metode .then () dan hanya menetapkan $ scope.data.artistData setelah janji kita dipenuhi dengan data iTunes. Anda akan melihat pengontrol kami sangat 'tipis' (Ini adalah praktik pengkodean yang baik). Semua logika dan data persisten kami terletak di layanan kami, bukan di controller kami.

2) Layanan
Mungkin hal terbesar yang perlu diketahui ketika berhadapan dengan menciptakan Layanan adalah bahwa itu dipakai dengan kata kunci 'baru'. Bagi Anda guru JavaScript ini harus memberi Anda petunjuk besar tentang sifat kode. Bagi Anda yang memiliki latar belakang terbatas dalam JavaScript atau bagi mereka yang tidak terlalu mengenal apa kata kunci 'baru' sebenarnya, mari kita tinjau beberapa dasar-dasar JavaScript yang pada akhirnya akan membantu kita dalam memahami sifat dari suatu Layanan.

Untuk benar-benar melihat perubahan yang terjadi ketika Anda menjalankan fungsi dengan kata kunci 'baru', mari kita membuat fungsi dan memohonnya dengan kata kunci 'baru', lalu mari kita tunjukkan apa yang dilakukan penerjemah ketika melihat kata kunci 'baru'. Hasil akhirnya akan sama.

Pertama mari kita buat konstruktor kita.

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

Ini adalah fungsi konstruktor JavaScript yang khas. Sekarang setiap kali kita memanggil fungsi Person menggunakan kata kunci 'baru', 'ini' akan terikat ke objek yang baru dibuat.

Sekarang mari kita tambahkan metode ke prototipe Person kita sehingga akan tersedia pada setiap instance 'kelas' Person kita.

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

Sekarang, karena kita meletakkan fungsi sayName pada prototipe, setiap instance dari Person akan dapat memanggil fungsi sayName untuk mengingatkan nama instance itu.

Sekarang kita memiliki fungsi konstruktor Person kita dan fungsi sayName kita pada prototipe, mari kita benar-benar membuat instance Person kemudian memanggil fungsi sayName.

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

Jadi secara keseluruhan kode untuk membuat konstruktor Person, menambahkan fungsi ke prototipe itu, membuat contoh Person, dan kemudian memanggil fungsi pada prototipe terlihat seperti ini.

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’

Sekarang mari kita lihat apa yang sebenarnya terjadi ketika Anda menggunakan kata kunci 'baru' dalam JavaScript. Hal pertama yang harus Anda perhatikan adalah bahwa setelah menggunakan 'baru' dalam contoh kami, kami dapat memanggil metode (sayName) di 'tyler' seolah-olah itu adalah objek - itu karena itu. Jadi pertama-tama, kita tahu bahwa konstruktor Person kita mengembalikan objek, apakah kita dapat melihatnya dalam kode atau tidak. Kedua, kita tahu bahwa karena fungsi sayName kita terletak pada prototipe dan tidak langsung pada contoh Person, objek yang dikembalikan fungsi Person harus didelegasikan ke prototipe pada pencarian gagal. Dalam istilah yang lebih sederhana, ketika kita memanggil tyler.sayName () interpreter mengatakan “OK, aku akan melihat objek 'tyler' yang baru saja kita buat, cari fungsi sayName, lalu panggil saja. Tunggu sebentar, saya tidak melihatnya di sini - yang saya lihat hanyalah nama dan umur, izinkan saya memeriksa prototipe. Yup, sepertinya ada di prototipe, biar saya sebut saja. ”.

Di bawah ini adalah kode untuk cara Anda berpikir tentang apa yang sebenarnya dilakukan kata kunci 'baru' dalam JavaScript. Ini pada dasarnya adalah contoh kode paragraf di atas. Saya telah menempatkan 'tampilan penerjemah' atau cara penerjemah melihat kode di dalam catatan.

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

Sekarang memiliki pengetahuan tentang apa kata kunci 'baru' sebenarnya dalam JavaScript, membuat Layanan di AngularJS harus lebih mudah dimengerti.

Hal terbesar untuk dipahami saat membuat Layanan adalah mengetahui bahwa Layanan dipakai dengan kata kunci 'baru'. Menggabungkan pengetahuan itu dengan contoh-contoh kami di atas, Anda sekarang harus mengakui bahwa Anda akan melampirkan properti dan metode Anda langsung ke 'ini' yang kemudian akan dikembalikan dari Layanan itu sendiri. Mari kita lihat ini dalam aksi.

Tidak seperti apa yang awalnya kami lakukan dengan contoh Pabrik, kita tidak perlu membuat objek lalu mengembalikan objek itu karena, seperti yang disebutkan berkali-kali sebelumnya, kita menggunakan kata kunci 'baru' sehingga penerjemah akan membuat objek itu, minta didelegasikan kepada itu prototipe, lalu kembalikan untuk kita tanpa kita harus melakukan pekerjaan.

Hal pertama yang pertama, mari kita buat fungsi 'pribadi' dan penolong kami. Ini seharusnya terlihat sangat akrab karena kami melakukan hal yang persis sama dengan pabrik kami. Saya tidak akan menjelaskan apa yang dilakukan setiap baris di sini karena saya melakukannya di contoh pabrik, jika Anda bingung, baca kembali contoh pabrik.

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

Sekarang, kami akan melampirkan semua metode kami yang akan tersedia di controller kami untuk 'ini'.

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

});

Sekarang sama seperti di pabrik kami, setArtist, getArtist, dan callItunes akan tersedia di mana pun controller kita lewati myService. Inilah pengendali myService (yang hampir persis sama dengan pengontrol pabrik kami).

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

Seperti yang saya sebutkan sebelumnya, setelah Anda benar-benar memahami apa yang 'baru' lakukan, Layanan hampir identik dengan pabrik di AngularJS.

3) Penyedia

Hal terbesar yang harus diingat tentang Penyedia adalah mereka satu-satunya layanan yang dapat Anda masuki ke bagian app.config dari aplikasi Anda. Ini sangat penting jika Anda perlu mengubah sebagian dari objek layanan Anda sebelum tersedia di tempat lain di aplikasi Anda. Meskipun sangat mirip dengan Layanan / Pabrik, ada beberapa perbedaan yang akan kita bahas.

Pertama, kami mengatur Penyedia kami dengan cara yang sama seperti yang kami lakukan dengan Layanan dan Pabrik kami. Variabel di bawah ini adalah fungsi 'pribadi' dan penolong kami.

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

* Lagi-lagi jika ada bagian dari kode di atas yang membingungkan, periksa bagian Pabrik di mana saya menjelaskan apa yang dilakukannya lebih detail.

Anda dapat menganggap Penyedia memiliki tiga bagian. Bagian pertama adalah variabel / fungsi 'pribadi' yang akan dimodifikasi / ditetapkan nanti (ditampilkan di atas). Bagian kedua adalah variabel / fungsi yang akan tersedia di fungsi app.config Anda dan karena itu tersedia untuk diubah sebelum tersedia di tempat lain (juga ditunjukkan di atas). Penting untuk dicatat bahwa variabel-variabel tersebut harus dilampirkan pada kata kunci 'ini'. Dalam contoh kita, hanya 'thingFromConfig' yang akan tersedia untuk diubah di app.config. Bagian ketiga (diperlihatkan di bawah) adalah semua variabel / fungsi yang akan tersedia di controller Anda ketika Anda memasukkan layanan 'myProvider' ke controller spesifik itu.

Saat membuat layanan dengan Penyedia, satu-satunya properti / metode yang akan tersedia di controller Anda adalah properti / metode yang dikembalikan dari fungsi $ get (). Kode di bawah ini menempatkan $ get pada 'this' (yang kita tahu pada akhirnya akan dikembalikan dari fungsi itu). Sekarang, fungsi $ get mengembalikan semua metode / properti yang kita inginkan tersedia di controller. Ini contoh kode.

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

Sekarang kode Penyedia lengkap terlihat seperti ini

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

Sekarang sama seperti di pabrik dan Layanan kami, setArtist, getArtist, dan callItunes akan tersedia di mana pun pengendali tempat kami memberikan myProvider. Inilah pengontrol myProvider (yang hampir persis sama dengan pengontrol pabrik / Layanan kami).

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

Seperti yang disebutkan sebelumnya, inti dari menciptakan layanan dengan Penyedia adalah untuk dapat mengubah beberapa variabel melalui fungsi app.config sebelum objek terakhir diteruskan ke sisa aplikasi. Mari kita lihat contohnya.

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

Sekarang Anda dapat melihat bagaimana 'thingFromConfig' sebagai string kosong di penyedia kami, tetapi ketika itu muncul di DOM, itu akan menjadi 'Kalimat ini telah ditetapkan ...'.


11
Satu-satunya bagian yang hilang dalam penulisan yang sangat baik ini adalah keuntungan relatif dari menggunakan layanan di atas pabrik; yang jelas dijelaskan dalam jawaban yang diterima oleh Lior
infinity

2
FWIW (mungkin tidak banyak), berikut adalah blogger yang mengambil masalah dengan Angular, dan tidak suka providerProvider codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
Bagian slogan 'JavaScript guru' adalah licik. : DI pikir jawaban ini sangat jelas. Ditulis dengan luar biasa.
amarmishra

4
TLDR Anda membutuhkan TLDR.
JensB

3
@JensB tl; dr - Pelajari Bereaksi.
Tyler McGinnis

512

Semua Layanan adalah lajang ; mereka akan instantiated sekali per aplikasi. Mereka bisa dari jenis apa pun , apakah itu primitif, objek literal, fungsi, atau bahkan turunan dari jenis kustom.

The value, factory, service, constant, dan providermetode yang semua penyedia. Mereka mengajarkan Injector bagaimana membuat Instansiasi Layanan.

Yang paling verbose, tetapi juga yang paling komprehensif adalah resep Provider. The tersisa empat jenis resep - Nilai, Pabrik, Jasa dan Constant - hanya sintaksis gula di atas resep penyedia .

  • The Nilai Resep adalah kasus yang paling sederhana, di mana Anda instantiate Layanan diri sendiri dan memberikan nilai instantiated ke injektor.
  • The Factory resep memberikan Injector fungsi pabrik yang mereka sebut saat dibutuhkan untuk instantiate layanan. Ketika dipanggil, fungsi pabrik membuat dan mengembalikan instance layanan. Ketergantungan Layanan disuntikkan sebagai argumen fungsi. Jadi menggunakan resep ini menambah kemampuan berikut:
    • Kemampuan untuk menggunakan layanan lain (memiliki ketergantungan)
    • Inisialisasi layanan
    • Inisialisasi tertunda / malas
  • The Resep Layanan ini hampir sama dengan resep Factory, tapi di sini Injector memanggil sebuah konstruktor dengan operator baru, bukan fungsi pabrik.
  • The Resep Provider biasanya berlebihan . Ini menambah satu lapisan tipuan dengan memungkinkan Anda untuk mengonfigurasi pembuatan pabrik.

    Anda harus menggunakan resep Penyedia hanya ketika Anda ingin mengekspos API untuk konfigurasi seluruh aplikasi yang harus dibuat sebelum aplikasi dimulai. Ini biasanya menarik hanya untuk layanan yang dapat digunakan kembali yang perilakunya mungkin perlu sedikit berbeda di antara aplikasi.

  • The Resep Konstan adalah seperti Nilai resep kecuali memungkinkan Anda untuk menentukan layanan yang tersedia di config fase. Lebih cepat dari layanan yang dibuat menggunakan resep Nilai. Tidak seperti Nilai, mereka tidak dapat didekorasi dengan menggunakandecorator .
Lihat dokumentasi penyedia .


2
Jadi servis dan pabrik pada dasarnya sama? Menggunakan salah satu dari yang lain tidak memberikan apa pun selain sintaksis alternatif?
Matt

2
@ Matt, ya, layanan adalah cara ringkas ketika Anda sudah memiliki fungsi Anda sendiri yang ingin Anda paparkan sebagai layanan. Dari docs: myApp.factory ('unicornLauncher', ["apiToken", function (apiToken) {kembalikan UnicornLauncher baru (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
janek

5
@ joshperry Sebagai pemula, saya telah mencari Google perbedaan antara layanan dan pabrik untuk sementara waktu. Saya setuju ini adalah jawaban terbaik yang pernah ada! Saya memahami layanan sebagai kelas layanan (mis. Kelas encoder / decoder), yang mungkin memiliki beberapa properti pribadi. Dan pabrik menyediakan seperangkat metode pembantu tanpa kewarganegaraan.
stanleyxu2005

3
Contoh Yaa dalam jawaban lain di atas gagal menjelaskan dengan jelas perbedaan inti layanan dan penyedia b / w yang disuntikkan pada saat resep ini dipakai.
Ashish Singh

223

Memahami Pabrik, Layanan, dan Penyedia AngularJS

Semua ini digunakan untuk berbagi objek singleton yang dapat digunakan kembali. Ini membantu untuk membagikan kode yang dapat digunakan kembali di aplikasi Anda / berbagai komponen / modul.

Dari Layanan Documents / Pabrik :

  • Instanated Lazily - Angular hanya instantiate layanan / pabrik ketika komponen aplikasi bergantung padanya.
  • Singletons - Setiap komponen yang bergantung pada layanan mendapat referensi ke instance tunggal yang dihasilkan oleh pabrik layanan.

Pabrik

Pabrik adalah fungsi tempat Anda dapat memanipulasi / menambahkan logika sebelum membuat objek, lalu objek yang baru dibuat akan dikembalikan.

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

Pemakaian

Ini bisa jadi hanya kumpulan fungsi seperti kelas. Oleh karena itu, ini dapat dipakai di pengontrol yang berbeda ketika Anda menyuntikkannya di dalam fungsi pengontrol / pabrik / direktif Anda. Ini dipakai hanya sekali per aplikasi.

Layanan

Cukup sambil melihat layanan berpikir tentang prototipe array. Layanan adalah fungsi yang membuat objek baru menggunakan kata kunci 'baru'. Anda dapat menambahkan properti dan fungsi ke objek layanan dengan menggunakan thiskata kunci. Tidak seperti pabrik, itu tidak mengembalikan apa pun (itu mengembalikan objek yang berisi metode / properti).

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

Pemakaian

Gunakan saat Anda perlu membagikan satu objek di seluruh aplikasi. Misalnya, rincian pengguna yang diautentikasi, metode / data yang dapat dibagikan, fungsi Utilitas dll.

Pemberi

Penyedia digunakan untuk membuat objek layanan yang dapat dikonfigurasi. Anda dapat mengonfigurasi pengaturan layanan dari fungsi konfigurasi. Ini mengembalikan nilai dengan menggunakan $get()fungsi. The $getFungsi dijalankan pada fase run di sudut.

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

Pemakaian

Ketika Anda perlu memberikan konfigurasi bijaksana untuk objek layanan Anda sebelum membuatnya tersedia, misalnya. misalkan Anda ingin mengatur URL API Anda berdasarkan Lingkungan Anda seperti dev, stageatauprod

CATATAN

Hanya penyedia yang akan tersedia dalam fase konfigurasi sudut, sementara layanan & pabrik tidak.

Semoga ini telah menjernihkan pemahaman Anda tentang Pabrik, Layanan, dan Penyedia .


1
Apa yang akan saya lakukan jika saya ingin memiliki layanan dengan antarmuka tertentu, tetapi memiliki dua implementasi yang berbeda, dan menyuntikkan masing-masing ke controller tetapi terikat ke berbagai negara menggunakan ui-router? misalnya membuat panggilan jarak jauh di satu negara, tetapi menulis ke penyimpanan lokal sebagai gantinya di negara lain. Dokumen penyedia mengatakan untuk digunakan 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, jadi sepertinya tidak mungkin, kan?
qix

191

Bagi saya, wahyu datang ketika saya menyadari bahwa mereka semua bekerja dengan cara yang sama: dengan menjalankan sesuatu sekali , menyimpan nilai yang mereka dapatkan, dan kemudian batuk nilai tersimpan yang sama ketika direferensikan melalui injeksi ketergantungan .

Katakanlah kita memiliki:

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

Perbedaan antara ketiganya adalah:

  1. aNilai yang disimpan berasal dari menjalankan fn.
  2. bNilai yang disimpan berasal dari newing fn.
  3. cNilai yang disimpan berasal dari pertama mendapatkan instance dengan newing fn, dan kemudian menjalankan $getmetode instance.

Yang berarti ada sesuatu seperti objek cache di dalam AngularJS, yang nilainya setiap injeksi hanya diberikan satu kali, ketika mereka telah disuntikkan pertama kali, dan di mana:

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

Inilah sebabnya kami menggunakan thisdalam layanan, dan mendefinisikan this.$getpenyedia dalam.


2
Saya juga paling suka jawaban ini. Inti dari semuanya adalah untuk menyediakan akses ke suatu objek kapan pun dibutuhkan melalui DI. Biasanya Anda baik-baik saja dengan factorys. Satu-satunya alasan serviceyang ada adalah bahasa seperti CoffeeScript, TypeScript, ES6 dll. Sehingga Anda dapat menggunakan sintaks kelasnya. Anda providerhanya perlu jika modul Anda digunakan di beberapa aplikasi dengan pengaturan yang berbeda dengan menggunakan app.config(). Jika layanan Anda adalah singleton murni atau mampu membuat instance sesuatu hanya tergantung pada implementasi Anda.
Andreas Linnert

137

Layanan vs penyedia vs pabrik:

Saya mencoba membuatnya tetap sederhana. Ini semua tentang konsep dasar JavaScript.

Pertama-tama, mari kita bicara tentang layanan di AngularJS!

Apa itu Layanan: Di AngularJS, Layanantidak lain adalah objek JavaScript tunggal yang dapat menyimpan beberapa metode atau properti yang berguna. Objek tunggal ini dibuat per ngApp (aplikasi Angular) dan dibagi di antara semua pengontrol dalam aplikasi saat ini. Ketika Angularjs instantiate objek layanan, itu mendaftarkan objek layanan ini dengan nama layanan yang unik. Jadi setiap kali ketika kita membutuhkan instance layanan, Angular mencari registri untuk nama layanan ini, dan mengembalikan referensi ke objek layanan. Sehingga kita dapat memanggil metode, mengakses properti dll pada objek layanan. Anda mungkin memiliki pertanyaan apakah Anda juga dapat menempatkan properti, metode pada objek lingkup pengontrol! Jadi mengapa Anda membutuhkan objek layanan? Jawabannya adalah: layanan dibagi di antara beberapa lingkup pengontrol. Jika Anda meletakkan beberapa properti / metode dalam objek lingkup pengontrol, itu akan tersedia untuk lingkup saat ini saja.

Jadi jika ada tiga ruang lingkup pengontrol, misalkan pengontrolA, pengontrolB dan pengontrolC, semua akan berbagi layanan yang sama.

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

Bagaimana cara membuat layanan?

AngularJS menyediakan berbagai metode untuk mendaftarkan layanan. Di sini kita akan berkonsentrasi pada tiga metode factory (..), service (..), provider (..);

Gunakan tautan ini untuk referensi kode

Fungsi pabrik:

Kita dapat mendefinisikan fungsi pabrik seperti di bawah ini.

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

AngularJS menyediakan metode 'factory (' serviceName ', fnFactory)' yang mengambil dua parameter, serviceName dan fungsi JavaScript. Angular membuat instance layanan dengan menjalankan fungsi fnFactory () seperti di bawah ini.

var serviceInstace = fnFactory();

Fungsi yang diteruskan dapat mendefinisikan objek dan mengembalikan objek itu. AngularJS hanya menyimpan referensi objek ini ke variabel yang diteruskan sebagai argumen pertama. Apa pun yang dikembalikan dari fnFactory akan terikat ke serviceInstance. Alih-alih mengembalikan objek, kita juga dapat mengembalikan fungsi, nilai, dll. Apapun yang akan kita kembalikan, akan tersedia untuk instance layanan.

Contoh:

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

Fungsi layanan:

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

Ini cara lain, kita bisa mendaftarkan layanan. Satu-satunya perbedaan adalah cara AngularJS mencoba untuk instantiate objek layanan. Kali ini sudut menggunakan kata kunci 'baru' dan memanggil fungsi konstruktor seperti di bawah ini.

var serviceInstance = new fnServiceConstructor();

Dalam fungsi konstruktor kita dapat menggunakan kata kunci 'ini' untuk menambahkan properti / metode ke objek layanan. contoh:

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

Fungsi penyedia:

Fungsi Provider () adalah cara lain untuk membuat layanan. Biarkan kami tertarik untuk membuat layanan yang hanya menampilkan beberapa pesan ucapan kepada pengguna. Tetapi kami juga ingin menyediakan fungsionalitas sehingga pengguna dapat mengatur pesan ucapan mereka sendiri. Dalam istilah teknis kami ingin membuat layanan yang dapat dikonfigurasi. Bagaimana kita bisa melakukan ini? Harus ada cara, sehingga aplikasi dapat mengirimkan pesan ucapan khusus mereka dan Angular akan membuatnya tersedia untuk fungsi pabrik / konstruktor yang membuat instance layanan kami. Dalam hal ini penyedia fungsi () melakukan pekerjaan. menggunakan fungsi provider () kita dapat membuat layanan yang dapat dikonfigurasi.

Kami dapat membuat layanan yang dapat dikonfigurasi menggunakan sintaksis penyedia seperti yang diberikan di bawah ini.

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

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

Bagaimana cara kerja sintaksis penyedia secara internal?

1.Provider object dibuat menggunakan fungsi konstruktor yang kami definisikan dalam fungsi provider kami.

var serviceProvider = new serviceProviderConstructor();

2.Fungsi yang kami lewati di app.config (), dijalankan. Ini disebut tahap konfigurasi, dan di sini kami memiliki kesempatan untuk menyesuaikan layanan kami.

configureService(serviceProvider);

3. Akhirnya layanan dibuat dengan memanggil metode $ get dari serviceProvider.

serviceInstance = serviceProvider.$get()

Kode sampel untuk membuat layanan menggunakan sintaks menyediakan:

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

Demo yang Bekerja

Ringkasan:


Pabrik menggunakan fungsi pabrik yang mengembalikan instance layanan. serviceInstance = fnFactory ();

Layanan menggunakan fungsi konstruktor dan Angular memanggil fungsi konstruktor ini menggunakan kata kunci 'baru' untuk membuat turunan layanan. serviceInstance = new fnServiceConstructor ();

Penyedia mendefinisikan fungsi providerConstructor, fungsi providerConstructor ini mendefinisikan fungsi pabrik $ get . Panggilan sudut $ get () untuk membuat objek layanan. Sintaks penyedia memiliki keuntungan tambahan untuk mengkonfigurasi objek layanan sebelum instantiated. serviceInstance = $ get ();



63

Pabrik

Anda memberi AngularJS fungsi, AngularJS akan melakukan cache dan menyuntikkan nilai kembali ketika pabrik diminta.

Contoh:

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

Pemakaian:

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

Layanan

Anda memberi AngularJS fungsi, AngularJS akan memanggil baru untuk membuat instance. Ini adalah contoh yang dibuat AngularJS yang akan di-cache dan disuntikkan ketika layanan diminta. Karena baru digunakan untuk membuat instantiate layanan, kata kunci ini valid dan merujuk ke instance.

Contoh:

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

Pemakaian:

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

Pemberi

Anda memberi AngularJS fungsi, dan AngularJS akan memanggil $getfungsinya. Ini adalah nilai balik dari $getfungsi yang akan di-cache dan disuntikkan ketika layanan diminta.

Penyedia memungkinkan Anda untuk mengkonfigurasi penyedia sebelum AngularJS memanggil $getmetode untuk mendapatkan injeksi.

Contoh:

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

Penggunaan (sebagai suntikan pada pengontrol)

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

Penggunaan (mengkonfigurasi penyedia sebelum $getdipanggil untuk membuat injeksi)

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

56

Saya perhatikan sesuatu yang menarik ketika bermain-main dengan penyedia.

Visibilitas dari suntikan berbeda untuk penyedia daripada untuk layanan dan pabrik. Jika Anda menyatakan AngularJS "konstan" (misalnya, myApp.constant('a', 'Robert');), Anda dapat menyuntikkannya ke layanan, pabrik, dan penyedia.

Tetapi jika Anda mendeklarasikan "nilai" AngularJS (misalnya., myApp.value('b', {name: 'Jones'});), Anda dapat menyuntikkannya ke layanan dan pabrik, tetapi BUKAN ke dalam fungsi pembuatan penyedia. Namun, Anda dapat menyuntikkannya ke $getfungsi yang Anda tetapkan untuk penyedia Anda. Ini disebutkan dalam dokumentasi AngularJS, tetapi mudah untuk dilewatkan. Anda dapat menemukannya di halaman% sediakan di bagian nilai dan metode konstan.

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

Ini adalah bagian yang sangat membingungkan bagi pemula dan saya telah mencoba menjelaskannya dengan kata-kata yang mudah

Layanan AngularJS: digunakan untuk berbagi fungsi utilitas dengan referensi layanan di controller. Layanan bersifat tunggal sehingga untuk satu layanan hanya satu instance yang dibuat di browser dan referensi yang sama digunakan di seluruh halaman.

Dalam layanan, kami membuat nama fungsi sebagai properti dengan objek ini .

AngularJS Factory: tujuan Factory juga sama dengan Service namun dalam hal ini kami membuat objek baru dan menambahkan fungsi sebagai properti dari objek ini dan pada akhirnya kami mengembalikan objek ini.

AngularJS Provider: tujuan ini sekali lagi sama namun Provider memberikan output fungsi $ get.

Menentukan dan menggunakan Layanan, Pabrik, dan Penyedia dijelaskan di http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider


2
Pabrik dan penyedia juga merupakan objek tunggal? Adakah scanrio di mana pabrik direkomendasikan daripada layanan?
Sunil Garg

34

Bagi saya cara terbaik dan paling sederhana untuk memahami perbedaannya adalah:

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

Bagaimana AngularJS instantiate komponen tertentu (disederhanakan):

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

// factory
var angularFactory = factory(injection);

Jadi, untuk layanan, yang menjadi komponen AngularJS adalah instance objek dari kelas yang diwakili oleh fungsi deklarasi layanan. Untuk pabrik, itu adalah hasil yang dikembalikan dari fungsi deklarasi pabrik. Pabrik mungkin berperilaku sama dengan layanan:

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

Cara berpikir paling sederhana adalah yang berikut:

  • Layanan adalah contoh objek tunggal. Gunakan layanan jika Anda ingin memberikan objek tunggal untuk kode Anda.
  • Pabrik adalah kelas. Gunakan pabrik jika Anda ingin memberikan kelas khusus untuk kode Anda (tidak dapat dilakukan dengan layanan karena mereka sudah dipakai)

Contoh 'kelas' pabrik diberikan dalam komentar di sekitar, serta perbedaan penyedia.


bagaimana sebuah layanan bisa menjadi singleton jika ia dipakai setiap kali digunakan? saya bisa mendapatkan kepala saya di sekitar itu ...
joe

Layanan hanya sekali dipakai selama penyelesaian ketergantungan, dan kemudian ketika Anda meminta layanan dari injector, Anda mendapatkan selalu contoh yang sama. Dapat dengan mudah memeriksa di sini: jsfiddle.net/l0co/sovtu55t/1 , silakan jalankan dengan konsol. Konsol menunjukkan bahwa layanan hanya dipakai satu kali.
Lukasz Frankowski

Oh begitu. Saya berharap untuk dapat secara harfiah new MyService()atau sesuatu :)
joe

33

Klarifikasi saya tentang masalah ini:

Pada dasarnya semua jenis yang disebutkan (layanan, pabrik, penyedia, dll.) Hanya membuat dan mengkonfigurasi variabel global (yang tentu saja global ke seluruh aplikasi), sama seperti variabel global kuno itu.

Sementara variabel global tidak direkomendasikan, penggunaan nyata dari variabel global ini adalah untuk memberikan injeksi ketergantungan , dengan meneruskan variabel ke pengontrol yang relevan.

Ada banyak tingkat komplikasi dalam menciptakan nilai untuk "variabel global":

  1. Constant
    Ini mendefinisikan konstanta aktual yang tidak boleh dimodifikasi selama keseluruhan aplikasi, seperti halnya konstanta dalam bahasa lain (sesuatu yang tidak dimiliki JavaScript).
  2. Nilai
    Ini adalah nilai atau objek yang dapat dimodifikasi, dan berfungsi sebagai beberapa variabel global, yang bahkan dapat disuntikkan ketika membuat layanan atau pabrik lain (lihat lebih lanjut tentang ini). Namun, itu harus berupa " nilai literal ", yang berarti bahwa seseorang harus menuliskan nilai aktual, dan tidak dapat menggunakan perhitungan atau logika pemrograman apa pun (dengan kata lain 39 atau myText atau {prop: "value"} tidak apa-apa, tetapi 2 +2 tidak).
  3. Pabrik
    Nilai yang lebih umum, yang memungkinkan untuk segera dihitung. Ia bekerja dengan melewatkan fungsi ke AngularJS dengan logika yang diperlukan untuk menghitung nilai dan AngularJS mengeksekusi itu, dan menyimpan nilai kembali dalam variabel bernama.
    Perhatikan bahwa dimungkinkan untuk mengembalikan objek (dalam hal ini akan berfungsi mirip dengan layanan ) atau fungsi (yang akan disimpan dalam variabel sebagai fungsi panggilan balik).
  4. Layanan
    Suatu layanan adalah versi pabrik yang lebih sederhana yang hanya valid ketika nilainya adalah objek, dan memungkinkan untuk menulis logika apa pun secara langsung dalam fungsi (seolah-olah itu akan menjadi konstruktor), serta mendeklarasikan dan mengakses properti objek menggunakan kata kunci ini .
  5. Penyedia
    Tidak seperti layanan yang merupakan versi pabrik yang disederhanakan , penyedia adalah cara yang lebih kompleks, tetapi lebih fleksibel untuk menginisialisasi variabel "global", dengan fleksibilitas terbesar adalah opsi untuk menetapkan nilai dari app.config.
    Ini berfungsi seperti menggunakan kombinasi layanan dan penyedia , dengan mengirimkan ke penyedia fungsi yang memiliki properti yang dideklarasikan menggunakan kata kunci ini , yang dapat digunakan dari app.config.
    Maka ia perlu memiliki fungsi $ .get terpisah yang dijalankan oleh AngularJS setelah menyetel properti di atas melalui app.configfile, dan fungsi $ .get ini berlaku seperti pabrik. di atas, dalam nilai pengembaliannya digunakan untuk menginisialisasi variabel "global".

26

Pemahaman saya sangat sederhana di bawah ini.

Pabrik: Anda cukup membuat objek di dalam pabrik dan mengembalikannya.

Layanan:

Anda hanya memiliki fungsi standar yang menggunakan kata kunci ini untuk mendefinisikan suatu fungsi.

Pemberi:

Ada $getobjek yang Anda tetapkan dan dapat digunakan untuk mendapatkan objek yang mengembalikan data.


Apakah Anda tidak mencampuradukkan Pabrik dan Layanan? Layanan menciptakan tempat pabrik kembali.
Flavien Volken

Saat Anda mendeklarasikan nama layanan sebagai argumen yang dapat disuntikkan, Anda akan diberikan instance fungsi. Dengan kata lain FunctionYouPassedToService () baru. Contoh objek ini menjadi objek layanan yang didaftarkan dan disuntikkan AngularJS nanti ke layanan / pengendali lain jika diperlukan. // factory Ketika Anda mendeklarasikan factoryname sebagai argumen injeksi, Anda akan diberikan nilai yang dikembalikan dengan menggunakan referensi fungsi yang diteruskan ke module.factory.
sajan

Oke, jadi ... di sudut pabrik adalah singleton di mana "layanan" sebenarnya adalah pabrik (dalam istilah pola desain umum)
Flavien Volken

25

Ringkasan dari dokumen Angular :

  • Ada lima jenis resep yang menentukan cara membuat objek: Nilai , Pabrik , Layanan , Penyedia , dan Konstan .
  • Pabrik dan Layanan adalah resep yang paling umum digunakan. Satu-satunya perbedaan di antara mereka adalah bahwa resep Layanan berfungsi lebih baik untuk objek jenis kustom, sementara Pabrik dapat menghasilkan primitif dan fungsi JavaScript.
  • The Provider resep adalah jenis resep inti dan semua yang lain yang hanya sintaksis gula di atasnya.
  • Penyedia adalah jenis resep paling kompleks. Anda tidak memerlukannya kecuali Anda sedang membangun sepotong kode yang dapat digunakan kembali yang membutuhkan konfigurasi global.

masukkan deskripsi gambar di sini


Jawaban terbaik dari SO:

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


20

Semua jawaban bagus sudah. Saya ingin menambahkan beberapa poin lagi pada Layanan dan Pabrik . Seiring dengan perbedaan antara layanan / pabrik. Dan seseorang juga dapat memiliki pertanyaan seperti:

  1. Haruskah saya menggunakan layanan atau pabrik? Apa bedanya?
  2. Apakah mereka melakukan hal yang sama atau memiliki perilaku yang sama?

Mari kita mulai dengan perbedaan antara Layanan dan pabrik:

  1. Keduanya Singletons : Setiap kali Angular menemukan ini sebagai dependensi pertama kali, itu membuat contoh layanan / pabrik. Setelah instance dibuat, instance yang sama digunakan selamanya.

  2. Dapat digunakan untuk memodelkan objek dengan perilaku : Keduanya dapat memiliki metode, variabel status internal, dan sebagainya. Meskipun cara Anda menulis kode itu akan berbeda.

Jasa:

Layanan adalah fungsi konstruktor, dan Angular akan instantiate dengan memanggil baru yourServiceName(). Ini berarti beberapa hal.

  1. Fungsi dan variabel instan akan menjadi properti dari this .
  2. Anda tidak perlu mengembalikan nilai. Ketika panggilan Angular new yourServiceName(), ia akan menerima thisobjek dengan semua properti yang Anda masukkan.

Contoh Contoh:

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

Ketika Angular menyuntikkan MyServicelayanan ini ke pengontrol yang bergantung padanya, pengontrol itu akan mendapatkan layanan MyServiceyang dapat memanggil fungsi, misalnya MyService.aServiceMethod ().

Hati-hati denganthis :

Karena layanan yang dibangun adalah objek, metode di dalamnya dapat merujuk ini ketika mereka dipanggil:

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

Anda mungkin tergoda untuk memanggil ScoreKeeper.setScorerantai janji, misalnya jika Anda menginisialisasi skor dengan meraihnya dari server: $http.get('/score').then(ScoreKeeper.setScore).Masalahnya adalah ini ScoreKeeper.setScoreakan dipanggil dengan thisterikat nulldan Anda akan mendapatkan kesalahan. Cara yang lebih baik$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)) . Apakah Anda memilih untuk menggunakan ini dalam metode layanan Anda atau tidak, berhati-hatilah bagaimana Anda menyebutnya.

Mengembalikan Nilai dari a Service :

Karena cara kerja konstruktor JavaScript, jika Anda mengembalikan nilai kompleks (i.e., an Object)dari aconstructor fungsi, pemanggil akan mendapatkan Objek itu daripada instance ini.

Ini berarti bahwa Anda pada dasarnya dapat menyalin-menempelkan contoh pabrik dari bawah, ganti factorydengan service, dan itu akan berhasil:

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

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

Jadi ketika Angular membangun layanan Anda dengan MyService baru (), ia akan mendapatkan objek api itu alih-alih instance MyService.

Ini adalah perilaku untuk setiap nilai kompleks (objek, fungsi) tetapi tidak untuk tipe primitif.

Pabrik:

Pabrik adalah fungsi lama sederhana yang mengembalikan nilai. Nilai pengembalian adalah apa yang disuntikkan ke dalam hal-hal yang bergantung pada pabrik. Pola khas pabrik di Angular adalah mengembalikan objek dengan fungsi sebagai properti, seperti ini:

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

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

  return api;
});

Nilai yang disuntikkan untuk ketergantungan pabrik adalah nilai pengembalian pabrik, dan tidak harus menjadi objek. Bisa jadi fungsi

Jawaban untuk pertanyaan 1 dan 2 di atas:

Untuk sebagian besar, tetap menggunakan pabrik untuk semuanya. Perilaku mereka lebih mudah dipahami. Tidak ada pilihan untuk membuat apakah akan mengembalikan nilai atau tidak, dan lebih jauh, tidak ada bug yang akan diperkenalkan jika Anda melakukan hal yang salah.

Saya masih menyebutnya sebagai "layanan" ketika saya berbicara tentang menyuntikkan mereka sebagai dependensi.

Perilaku Servis / Pabrik sangat mirip, dan beberapa orang akan mengatakan bahwa keduanya baik-baik saja. Itu agak benar, tetapi saya merasa lebih mudah untuk mengikuti saran dari panduan gaya John Papa dan hanya tetap dengan pabrik. **


16

Klarifikasi tambahan adalah bahwa pabrik dapat membuat fungsi / primitif, sementara layanan tidak bisa. Lihatlah jsFiddle ini berdasarkan Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .

Pabrik mengembalikan fungsi yang dapat dipanggil:

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

Pabrik juga dapat mengembalikan objek dengan metode yang dapat dipanggil:

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

Layanan mengembalikan objek dengan metode yang dapat dipanggil:

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

Untuk lebih jelasnya, lihat posting yang saya tulis tentang perbedaannya: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


16

Sudah ada jawaban bagus, tapi saya hanya ingin membagikan yang ini.

Pertama-tama: Penyedia adalah cara / resep untuk membuatservice (objek tunggal) yang seharusnya disuntikkan oleh $ injector (bagaimana AngulaJS berjalan tentang pola IoC).

Dan Nilai, Pabrik, Layanan dan Konstan (4 cara) - gula sintaksis atas Penyedia cara / penerima.

Ada Service vs Factorybagian yang telah dibahas: https://www.youtube.com/watch?v=BLzNCkPn3ao

Layanan adalah tentang newkata kunci sebenarnya yang seperti yang kita ketahui melakukan 4 hal:

  1. menciptakan objek baru
  2. menautkannya ke prototype objeknya
  3. menghubungkan context kethis
  4. dan kembali this

Dan Pabrik adalah semua tentang Pola Pabrik - berisi fungsi yang mengembalikan Objek seperti Layanan itu.

  1. kemampuan untuk menggunakan layanan lain (memiliki ketergantungan)
  2. inisialisasi layanan
  3. inisialisasi tertunda / malas

Dan video sederhana / singkat ini: mencakup juga Penyedia : https://www.youtube.com/watch?v=HvTZbQ_hUZY (di sana Anda dapat melihat bagaimana mereka beralih dari satu pabrik ke penyedia lainnya)

Resep penyedia sebagian besar digunakan dalam konfigurasi aplikasi, sebelum aplikasi sepenuhnya dimulai / diinisialisasi.


14

Setelah membaca semua posting ini, itu membuat saya lebih bingung .. Tapi tetap saja semua informasi berharga .. akhirnya saya menemukan tabel berikut yang akan memberikan informasi dengan perbandingan sederhana

  • Injektor menggunakan resep untuk membuat dua jenis objek: layanan dan objek tujuan khusus
  • Ada lima jenis resep yang menentukan cara membuat objek: Nilai, Pabrik, Layanan, Penyedia, dan Konstan.
  • Pabrik dan Layanan adalah resep yang paling umum digunakan. Satu-satunya perbedaan di antara mereka adalah bahwa resep Layanan berfungsi lebih baik untuk objek jenis kustom, sementara Pabrik dapat menghasilkan primitif dan fungsi JavaScript.
  • Resep Provider adalah tipe resep inti dan yang lainnya hanyalah gula sintaksis.
  • Penyedia adalah jenis resep paling kompleks. Anda tidak memerlukannya kecuali Anda sedang membangun sepotong kode yang dapat digunakan kembali yang membutuhkan konfigurasi global.
  • Semua objek tujuan khusus kecuali untuk Kontroler didefinisikan melalui resep Pabrik.

masukkan deskripsi gambar di sini

Dan untuk pemula pahami: - Ini mungkin tidak memperbaiki use case tetapi pada level tinggi inilah yang digunakan untuk ketiganya.

  1. Jika Anda ingin menggunakan fungsi konfigurasi modul sudut harus dibuat sebagai penyedia

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

  1. Panggilan Ajax atau integrasi pihak ketiga harus menjadi layanan .
  2. Untuk manipulasi data, buatlah itu sebagai pabrik

Untuk skenario dasar, pabrik & Layanan berperilaku sama.


13

Berikut adalah beberapa kode platfile yang saya buat sebagai templat kode untuk objek pabrik di AngularjS. Saya telah menggunakan Car / CarFactory sebagai contoh untuk menggambarkan. Membuat kode implementasi sederhana di controller.

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

Ini adalah contoh sederhana. Saya menggunakan beberapa pustaka pihak ketiga yang mengharapkan objek "Posisi" yang mengekspos lintang dan bujur, tetapi melalui properti objek yang berbeda. Saya tidak ingin meretas kode vendor, jadi saya menyesuaikan objek "Posisi" yang saya berikan.

    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

Menggunakan referensi halaman ini dan dokumentasi (yang tampaknya telah sangat meningkat sejak terakhir kali saya melihat), saya mengumpulkan demo dunia nyata (-ish) berikut ini yang menggunakan 4 dari 5 rasa penyedia; Penyedia Nilai, Konstan, Pabrik, dan peniupan penuh.

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>

aplikasi

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

Demo kerja .


12

Jawaban ini membahas topik / pertanyaan

bagaimana Factory, Service dan Constant - hanya gula sintaksis di atas resep penyedia?

ATAU

bagaimana pabrik, layanan dan penyedia simailar secara internal

pada dasarnya yang terjadi adalah

Ketika Anda membuatnya factory()menetapkan Anda functionberikan dalam argumen kedua ke penyedia $getdan mengembalikannya ( provider(name, {$get:factoryFn })), yang Anda dapatkan hanyalah providertetapi tidak ada properti / metode selain$get itu provider(artinya Anda tidak dapat mengonfigurasi ini)

Kode sumber pabrik

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

Ketika membuatnya service()mengembalikan Anda memberikan pabrik () dengan functionyang menyuntikkan constructor(mengembalikan instance dari konstruktor yang Anda berikan dalam layanan Anda) dan mengembalikannya

Kode sumber layanan

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

Jadi pada dasarnya dalam kedua kasus Anda akhirnya mendapatkan penyedia $ bisa diatur untuk fungsi yang Anda berikan, tetapi Anda bisa memberikan apa pun lebih dari $ dapatkan karena Anda awalnya dapat menyediakan di provider () untuk blok konfigurasi


11

Saya tahu banyak jawaban yang sangat baik tetapi saya harus berbagi pengalaman saya menggunakan
1. serviceuntuk sebagian besar kasus default
2. factorydigunakan untuk membuat layanan contoh khusus

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

dan menggunakan:

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

Agak terlambat ke pesta. Tapi saya pikir ini lebih bermanfaat bagi yang ingin belajar (atau memiliki kejelasan) tentang pengembangan Layanan Kustom JS Angular menggunakan metodologi pabrik, layanan, dan penyedia.

Saya menemukan video ini yang menjelaskan dengan jelas tentang metodologi pabrik, layanan, dan penyedia untuk mengembangkan Layanan Kustom AngularJS:

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

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

Kode yang diposting di sini disalin langsung dari sumber di atas, untuk memberi manfaat bagi pembaca.

Kode untuk layanan kustom berbasis "pabrik" adalah sebagai berikut (yang berlaku dengan versi sinkronisasi dan async bersamaan dengan memanggil layanan 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;
  }
]);

Kode untuk metodologi "layanan" untuk Layanan Kustom (ini sangat mirip dengan 'pabrik', tetapi berbeda dari sudut pandang sintaksis):

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

}]);

Kode untuk metodologi "penyedia" untuk Layanan Kustom (ini diperlukan, jika Anda ingin mengembangkan layanan yang dapat dikonfigurasi):

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

Akhirnya UI yang bekerja dengan salah satu layanan di atas:

<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

Untuk memperjelas beberapa hal, dari sumber AngularJS, Anda dapat melihat layanan memanggil fungsi pabrik yang kemudian memanggil fungsi penyedia:

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

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

9

Mari kita bahas tiga cara menangani logika bisnis di AngularJS dengan cara sederhana: ( Terinspirasi oleh kursus Coursera AngularJS Yaakov )

LAYANAN :

Sintaksis:

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>

Fitur Layanan:

  1. Lazily Instantiated : Jika tidak disuntikkan, ia tidak akan pernah dipakai. Jadi untuk menggunakannya harus menyuntikkannya ke modul.
  2. Singleton : Jika disuntikkan ke beberapa modul, semua akan memiliki akses hanya ke satu instance tertentu. Itu sebabnya sangat nyaman untuk berbagi data di seluruh pengontrol yang berbeda.

PABRIK

Pertama mari kita lihat sintaks:

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

Sekarang menggunakan dua di atas di controller:

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

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

Fitur pabrik:

  1. Mengikuti pola desain pabrik. Pabrik adalah tempat sentral yang menghasilkan benda atau fungsi baru.
  2. Tidak hanya menghasilkan singleton, tetapi layanan yang dapat disesuaikan.
  3. The .service()Metode adalah pabrik yang selalu menghasilkan jenis yang sama dari layanan, yang tunggal, dan tanpa cara mudah untuk mengkonfigurasi perilaku itu. Itu .service()metode biasanya digunakan sebagai jalan pintas untuk sesuatu yang tidak memerlukan apapun konfigurasi.

PEMBERI

Mari kita lihat Sintaks lebih dulu:

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

}

Fitur Penyedia:

  1. Penyedia adalah metode yang paling fleksibel untuk menciptakan layanan di Angular.
  2. Tidak hanya kita dapat membuat pabrik yang dapat dikonfigurasi secara dinamis, tetapi pada saat menggunakan pabrik, dengan metode penyedia, kita dapat mengkustomisasi pabrik hanya sekali pada saat bootstrap seluruh aplikasi kita.
  3. Pabrik kemudian dapat digunakan di seluruh aplikasi dengan pengaturan khusus. Dengan kata lain, kita dapat mengkonfigurasi pabrik ini sebelum aplikasi dimulai. Bahkan dalam dokumentasi sudut disebutkan bahwa metode penyedia adalah apa yang sebenarnya dieksekusi di belakang layar ketika kita mengkonfigurasi layanan kami dengan salah satu .serviceatau .factorymetode.
  4. Ini $getadalah fungsi yang secara langsung dilampirkan ke instance penyedia. Fungsi itu adalah fungsi pabrik . Dengan kata lain, itu hanya seperti salah satu yang kita gunakan untuk memberikan kepada .factorymetode. Dalam fungsi itu, kami membuat layanan kami sendiri. Properti ini $get, itulah fungsi, yang membuat penyedia menjadi penyedia . AngularJS mengharapkan penyedia memiliki properti $ get yang nilainya merupakan fungsi yang akan diperlakukan Angular sebagai fungsi pabrik. Tetapi apa yang membuat seluruh pengaturan penyedia ini sangat istimewa, adalah kenyataan bahwa kami dapat menyediakan beberapa configobjek di dalam penyedia layanan, dan yang biasanya disertai dengan default yang nantinya dapat kami timpa dalam langkah tersebut, di mana kami dapat mengonfigurasi seluruh aplikasi.

7

Pabrik: Pabrik Anda benar-benar membuat objek di dalam pabrik dan mengembalikannya.
layanan: Layanan Anda hanya memiliki fungsi standar yang menggunakan kata kunci ini untuk mendefinisikan fungsi.
penyedia: Penyedia ada $ membuat Anda mendefinisikan dan itu dapat digunakan untuk mendapatkan objek yang mengembalikan data.


7

Intinya, Penyedia, Pabrik, dan Layanan adalah semua Layanan. Pabrik adalah kasus khusus dari suatu Layanan ketika yang Anda butuhkan hanyalah fungsi $ get (), memungkinkan Anda untuk menulisnya dengan kode yang lebih sedikit.

Perbedaan utama antara Layanan, Pabrik, dan Penyedia adalah kompleksitasnya. Layanan adalah bentuk paling sederhana, Pabrik sedikit lebih kuat, dan Penyedia dapat dikonfigurasi saat runtime.

Berikut ini adalah ringkasan kapan harus menggunakan masing-masing:

Pabrik : Nilai yang Anda berikan perlu dihitung berdasarkan data lain.

Layanan : Anda mengembalikan objek dengan metode.

Penyedia : Anda ingin dapat mengkonfigurasi, selama fase konfigurasi, objek yang akan dibuat sebelum dibuat. Gunakan Penyedia sebagian besar dalam konfigurasi aplikasi, sebelum aplikasi sepenuhnya diinisialisasi.


erm. Nilai, Pabrik, Layanan, dan Konstan - hanyalah gula sintaksis di atas resep penyedia. Dokumen Angularjs - penyedia
Sudarshan_SMD

ya saya setuju, sekarang dengan sudut 4 kita tidak memiliki sakit kepala ini lagi
eGhoul

4

1.Layanan adalah objek tunggal yang dibuat saat diperlukan dan tidak pernah dibersihkan hingga akhir siklus hidup aplikasi (saat browser ditutup). Pengendali dihancurkan dan dibersihkan ketika mereka tidak lagi diperlukan.

2. Cara termudah untuk membuat layanan adalah dengan menggunakan metode factory (). Metode factory () memungkinkan kita untuk mendefinisikan layanan dengan mengembalikan objek yang berisi fungsi layanan dan data layanan. Fungsi definisi layanan adalah tempat kami menempatkan layanan injeksi kami, seperti $ http dan $ q. Ex:

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
    // our factory definition
user: {},
setName: function(newName) {
      service.user['name'] = newName;
    },
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });

Menggunakan pabrik () di aplikasi kami

Sangat mudah untuk menggunakan pabrik di aplikasi kita karena kita bisa menyuntikkannya di mana kita membutuhkannya saat dijalankan.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Metode service (), di sisi lain memungkinkan kita untuk membuat layanan dengan mendefinisikan fungsi konstruktor. Kita dapat menggunakan objek prototipikal untuk mendefinisikan layanan kami, bukan objek javascript mentah. Mirip dengan metode factory (), kami juga akan mengatur injeksi dalam definisi fungsi.
  2. Cara tingkat terendah untuk membuat layanan adalah dengan menggunakan metode menyediakan (). Ini adalah satu-satunya cara untuk membuat layanan yang dapat kita konfigurasi menggunakan fungsi .config (). Tidak seperti metode sebelumnya, kami akan menetapkan injeksi dalam definisi fungsi yang didefinisikan. $ Get () ini.

-3

Gula sintaksis adalah perbedaannya . Hanya penyedia yang dibutuhkan. Atau dengan kata lain hanya provider yang bersudut nyata, semua yang lain diturunkan (untuk mengurangi kode). Ada versi sederhana juga, yang disebut Value () yang mengembalikan nilai saja, tidak ada perhitungan atau fungsi. Bahkan Nilai diperoleh dari penyedia!

Jadi mengapa komplikasi seperti itu, mengapa kita tidak bisa menggunakan penyedia saja dan melupakan yang lainnya? Seharusnya membantu kita menulis kode dengan mudah dan berkomunikasi dengan lebih baik. Dan balasan toungue-in-pipi akan, semakin kompleks itu semakin baik penjualan kerangka kerja akan.


  • Penyedia yang dapat mengembalikan nilai = Nilai
  • Penyedia yang dapat langsung membuat dan mengembalikan = Pabrik (+ Nilai)
  • Penyedia yang dapat instantiate + melakukan sesuatu = Layanan (+ Pabrik, + Nilai)
  • Penyedia = harus mengandung properti yang disebut $ get (+ Factory, + Service, + Value)

Injeksi sudut memberi kita petunjuk pertama dalam mencapai kesimpulan ini.

"$ injector digunakan untuk mengambil instance objek sebagaimana didefinisikan oleh penyedia " bukan layanan, bukan pabrik tetapi penyedia.

Dan jawaban yang lebih baik adalah: "Layanan Angular dibuat oleh pabrik layanan. Pabrik-pabrik layanan ini adalah fungsi yang, pada gilirannya, diciptakan oleh penyedia layanan. Penyedia layanan adalah fungsi konstruktor. Ketika instantiated mereka harus mengandung properti disebut $ get, yang memegang fungsi pabrik layanan. "

Jadi penyedia utama dan injektor dan semua akan jatuh pada tempatnya :). Dan itu menjadi menarik dalam Script ketika $ get dapat diimplementasikan dalam penyedia dengan mewarisi dari IServiceProvider.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.