Каковы различия между Service
, Provider
и Factory
в AngularJS?
service.factory
. Не хотел усложнять эту тему дальше.
Каковы различия между Service
, Provider
и Factory
в AngularJS?
service.factory
. Не хотел усложнять эту тему дальше.
Ответы:
Из списка рассылки AngularJS я получил удивительную ветку, в которой объясняются сервисы против фабрики, против провайдеров и их использование. Составление ответов:
Синтаксис: module.service( 'serviceName', function );
Результат: при объявлении serviceName в качестве вводимого аргумента вам будет предоставлен экземпляр функции. Другими словами new FunctionYouPassedToService()
.
Синтаксис: module.factory( 'factoryName', function );
Результат: при объявлении factoryName в качестве вводимого аргумента вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory .
Синтаксис: module.provider( 'providerName', function );
Результат: При объявлении providerName в качестве вводимого аргумента вам будет предоставлено (new ProviderFunction()).$get()
. Функция конструктора ProviderFunction
создается перед вызовом метода $ get - это ссылка на функцию, переданную в module.provider.
Преимущество провайдеров заключается в том, что их можно настраивать на этапе настройки модуля.
Смотрите здесь для предоставленного кода.
Вот большое дальнейшее объяснение Миско:
provide.value('a', 123);
function Controller(a) {
expect(a).toEqual(123);
}
В этом случае инжектор просто возвращает значение как есть. Но что, если вы хотите вычислить значение? Тогда используйте фабрику
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
Такова factory
функция, которая отвечает за создание стоимости. Обратите внимание, что фабричная функция может запрашивать другие зависимости.
Но что, если вы хотите быть более интересным и иметь класс под названием Greeter?
function Greeter(a) {
this.greet = function() {
return 'Hello ' + a;
}
}
Тогда для создания экземпляра вам придется написать
provide.factory('greeter', function(a) {
return new Greeter(a);
});
Тогда мы могли бы попросить «приветствовать» в контроллере, как это
function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual('Hello 123');
}
Но это слишком многословно. Более короткий способ написать это будетprovider.service('greeter', Greeter);
Но что, если мы хотим настроить Greeter
класс до внедрения? Тогда мы могли бы написать
provide.provider('greeter2', function() {
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.greet = function() {
return salutation + ' ' + a;
}
}
this.$get = function(a) {
return new Greeter(a);
};
});
Тогда мы можем сделать это:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
В качестве примечания, service
, factory
, и value
все получены от поставщика.
provider.service = function(name, Class) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.instantiate(Class);
};
});
}
provider.factory = function(name, factory) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.invoke(factory);
};
});
}
provider.value = function(name, value) {
provider.factory(name, function() {
return value;
});
};
toEqual
и greeter.Greet
есть. Почему бы не использовать что-то более реальное и подходящее?
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>
this
меняет контекст в $get
функции? - вы больше не обращаетесь к конкретному провайдеру в этой функции.
this
фактически не меняет контекст, потому что то, что вызывается, это new Provider()
. $ Get (), где Provider
передается функция app.provider
. Это значит, что он $get()
вызывается как метод на построенном объекте Provider
, поэтому мы this
будем ссылаться на него, Provider
как показывает пример.
Unknown provider: helloWorldProvider <- helloWorld
при запуске этого локально? Комментируя это, та же ошибка для двух других примеров. Есть ли какая-то скрытая конфигурация провайдера? (Angular 1.0.8) - Найдено: stackoverflow.com/questions/12339272/…
TL; DR
1) Когда вы используете Factory, вы создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Когда вы передадите эту фабрику в свой контроллер, эти свойства объекта теперь будут доступны в этом контроллере через вашу фабрику.
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) Когда вы используете Сервис , AngularJS создает его за кулисами с ключевым словом «new». Из-за этого вы добавите свойства в «this», и сервис вернет «this». Когда вы передаете услугу в свой контроллер, эти свойства в «this» теперь будут доступны на этом контроллере через ваш сервис.
app.controller(‘myServiceCtrl’, function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service(‘myService’, function(){
var _artist = ‘Nelly’;
this.getArtist = function(){
return _artist;
}
});
3) Поставщики - это единственная услуга, которую вы можете передать в функцию .config (). Используйте провайдера, если вы хотите предоставить конфигурацию всего модуля для объекта службы, прежде чем сделать его доступным.
app.controller(‘myProvider’, function($scope, myProvider){
$scope.artist = myProvider.getArtist();
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
app.provider(‘myProvider’, function(){
//Only the next two lines are available in the app.config()
this._artist = ‘’;
this.thingFromConfig = ‘’;
this.$get = function(){
var that = this;
return {
getArtist: function(){
return that._artist;
},
thingOnConfig: that.thingFromConfig
}
}
});
app.config(function(myProviderProvider){
myProviderProvider.thingFromConfig = ‘This was set in config’;
});
Не TL; DR
1)
Фабрики - это самый популярный способ создания и настройки сервиса. Там действительно не намного больше, чем то, что сказал TL; DR. Вы просто создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Затем, когда вы передадите фабрику в свой контроллер, эти свойства объекта теперь будут доступны в этом контроллере через вашу фабрику. Более подробный пример приведен ниже.
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
Теперь любые свойства, которые мы прикрепляем к «сервису», будут нам доступны, когда мы передадим «myFactory» в наш контроллер.
Теперь давайте добавим некоторые «приватные» переменные в нашу функцию обратного вызова. Они не будут напрямую доступны из контроллера, но мы в конечном итоге настроим некоторые методы получения / установки для «службы», чтобы иметь возможность изменять эти «частные» переменные при необходимости.
app.factory(‘myFactory’, function($http, $q){
var service = {};
var baseUrl = ‘https://itunes.apple.com/search?term=’;
var _artist = ‘’;
var _finalUrl = ‘’;
var makeUrl = function(){
_artist = _artist.split(‘ ‘).join(‘+’);
_finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
return _finalUrl
}
return service;
});
Здесь вы заметите, что мы не привязываем эти переменные / функцию к 'service'. Мы просто создаем их, чтобы потом использовать или модифицировать их.
Теперь, когда наши вспомогательные / закрытые переменные и функции на месте, давайте добавим некоторые свойства к объекту 'service'. Все, что мы ставим на «сервис», можно напрямую использовать внутри любого контроллера, в который мы передаем «myFactory».
Мы собираемся создать методы setArtist и getArtist, которые просто возвращают или устанавливают художника. Мы также собираемся создать метод, который будет вызывать iTunes API с нашим созданным URL. Этот метод возвращает обещание, которое будет выполнено, как только данные вернутся из iTunes API. Если у вас не было большого опыта использования обещаний в AngularJS, я настоятельно рекомендую глубоко погрузиться в них.
Ниже setArtist принимает художника и позволяет установить художника. getArtist возвращает художника. callItunes сначала вызывает makeUrl (), чтобы создать URL, который мы будем использовать с нашим запросом $ http. Затем он устанавливает объект обещания, делает запрос $ http с нашим окончательным URL, а затем, так как $ http возвращает обещание, мы можем вызвать .success или .error после нашего запроса. Затем мы выполняем наше обещание с помощью данных iTunes или отклоняем его с сообщением «Произошла ошибка».
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
service.setArtist = function(artist){
_artist = artist;
}
service.getArtist = function(){
return _artist;
}
service.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
return service;
});
Теперь наша фабрика завершена. Теперь мы можем внедрить 'myFactory' в любой контроллер, и тогда мы сможем вызывать наши методы, которые мы прикрепили к нашему сервисному объекту (setArtist, getArtist и callItunes).
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.data = {};
$scope.updateArtist = function(){
myFactory.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myFactory.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
В контроллере выше мы вводим в сервис «myFactory». Затем мы устанавливаем свойства нашего объекта $ scope с данными из myFactory. Единственный сложный код выше, если вы никогда не имели дело с обещаниями раньше. Поскольку callItunes возвращает обещание, мы можем использовать метод .then () и устанавливать $ scope.data.artistData только после того, как наше обещание будет выполнено с данными iTunes. Вы заметите, что наш контроллер очень «тонкий» (это хорошая практика кодирования). Вся наша логика и постоянные данные находятся в нашем сервисе, а не в нашем контроллере.
2) Сервис
Возможно, самая важная вещь, которую нужно знать при создании Сервиса, это то, что он создается с ключевым словом «new». Для вас, гуру JavaScript, это должно дать вам подсказку о природе кода. Для тех из вас, кто имеет ограниченный опыт работы с JavaScript, или тех, кто не слишком знаком с тем, что на самом деле делает ключевое слово «new», давайте рассмотрим некоторые основы JavaScript, которые в конечном итоге помогут нам понять природу Сервиса.
Чтобы действительно увидеть изменения, которые происходят при вызове функции с ключевым словом «new», давайте создадим функцию и вызовем ее с ключевым словом «new», а затем покажем, что делает интерпретатор, когда видит ключевое слово «new». Конечные результаты будут одинаковыми.
Сначала давайте создадим наш конструктор.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Это типичная функция конструктора JavaScript. Теперь всякий раз, когда мы вызываем функцию Person с помощью ключевого слова new, this будет привязано к вновь созданному объекту.
Теперь давайте добавим метод в прототип нашего Person, чтобы он был доступен для каждого экземпляра нашего класса Person.
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
Теперь, поскольку мы поместили функцию sayName в прототип, каждый экземпляр Person сможет вызывать функцию sayName в порядке оповещения об имени этого экземпляра.
Теперь, когда у нас есть функция конструктора Person и наша функция sayName в ее прототипе, давайте создадим экземпляр Person, а затем вызовем функцию sayName.
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Таким образом, весь код для создания конструктора Person, добавления функции к его прототипу, создания экземпляра Person и последующего вызова функции для его прототипа выглядит следующим образом.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Теперь давайте посмотрим, что на самом деле происходит, когда вы используете ключевое слово «new» в JavaScript. Первое, что вы должны заметить, это то, что после использования «new» в нашем примере мы можем вызвать метод (sayName) для «tyler» так же, как если бы это был объект - так оно и есть. Итак, во-первых, мы знаем, что наш конструктор Person возвращает объект, видим ли мы это в коде или нет. Во-вторых, мы знаем, что поскольку наша функция sayName расположена в прототипе, а не непосредственно в экземпляре Person, объект, который возвращает функция Person, должен делегировать своему прототипу при неудачных поисках. Проще говоря, когда мы вызываем tyler.sayName (), интерпретатор говорит: «Хорошо, я собираюсь посмотреть на только что созданный объект« tyler », найти функцию sayName, а затем вызвать ее. Подожди, я не вижу этого здесь - все, что я вижу, это имя и возраст, позвольте мне проверить прототип. Да, похоже, что это на прототипе, позвольте мне назвать это ».
Ниже приведен код того, как вы можете думать о том, что на самом деле делает ключевое слово «новый» в JavaScript. Это в основном пример кода вышеупомянутого абзаца. Я поместил «представление интерпретатора» или то, как интерпретатор видит код внутри заметок.
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;
}
Теперь, имея представление о том, что на самом деле делает ключевое слово «новое» в JavaScript, создание службы в AngularJS должно быть проще для понимания.
Самая важная вещь, которую нужно понять при создании Сервиса, это знание того, что Сервисы создаются с помощью ключевого слова «new». Объединяя эти знания с нашими примерами выше, вы теперь должны понимать, что вы будете привязывать свои свойства и методы непосредственно к «this», которое затем будет возвращено из самой Службы. Давайте посмотрим на это в действии.
В отличие от того, что мы изначально делали с примером Factory, нам не нужно создавать объект, а затем возвращать этот объект, потому что, как упоминалось много раз ранее, мы использовали ключевое слово «new», поэтому интерпретатор создаст этот объект, предоставив ему делегирование это прототип, а затем верните его нам без необходимости выполнять работу.
Прежде всего, давайте создадим нашу «приватную» и вспомогательную функцию. Это должно выглядеть очень знакомо, так как мы сделали то же самое с нашим заводом. Я не буду объяснять, что здесь делает каждая строка, потому что я сделал это в заводском примере, если вы не уверены, перечитайте заводской пример.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
});
Теперь мы прикрепим все наши методы, которые будут доступны в нашем контроллере, к «this».
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.setArtist = function(artist){
_artist = artist;
}
this.getArtist = function(){
return _artist;
}
this.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
});
Теперь, как и на нашей фабрике, setArtist, getArtist и callItunes будут доступны в любом контроллере, в который мы передаем myService. Вот контроллер myService (который почти такой же, как наш заводской контроллер).
app.controller('myServiceCtrl', function($scope, myService){
$scope.data = {};
$scope.updateArtist = function(){
myService.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myService.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
Как я уже упоминал ранее, когда вы действительно понимаете, что делает «новое», Сервисы практически идентичны фабрикам в AngularJS.
3) Провайдер
Самое важное, что нужно помнить о провайдерах, это то, что они являются единственной службой, которую вы можете передать в часть app.config вашего приложения. Это имеет огромное значение, если вам нужно изменить какую-то часть вашего сервисного объекта, прежде чем он станет доступен везде в вашем приложении. Хотя это очень похоже на Услуги / Фабрики, есть несколько различий, которые мы обсудим.
Сначала мы настраиваем нашего провайдера аналогично тому, как мы работали с нашим сервисом и фабрикой. Переменные ниже являются нашей «приватной» и вспомогательной функцией.
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below.
this.thingFromConfig = ‘’;
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
}
* Опять же, если какая-либо часть приведенного выше кода вводит в заблуждение, ознакомьтесь с разделом «Фабрика», где я объясняю, для чего все это более подробно.
Вы можете думать о провайдерах как о трех разделах. Первый раздел - это «частные» переменные / функции, которые будут изменены / установлены позже (показано выше). Второй раздел - это переменные / функции, которые будут доступны в вашей функции app.config и, следовательно, доступны для изменения до того, как они станут доступны где-либо еще (также показано выше). Важно отметить, что эти переменные должны быть присоединены к ключевому слову this. В нашем примере, только 'thingFromConfig' будет доступен для изменения в app.config. Третий раздел (показанный ниже) - это все переменные / функции, которые будут доступны в вашем контроллере, когда вы передадите службу myProvider в этот конкретный контроллер.
При создании службы с помощью Provider в вашем контроллере будут доступны только те свойства / методы, которые возвращаются из функции $ get (). Приведенный ниже код помещает $ get в this (которое, как мы знаем, будет возвращено из этой функции). Теперь эта функция $ get возвращает все методы / свойства, которые мы хотим быть доступными в контроллере. Вот пример кода.
this.$get = function($http, $q){
return {
callItunes: function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
Теперь полный код провайдера выглядит следующим образом
app.provider('myProvider', function(){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below
this.thingFromConfig = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.$get = function($http, $q){
return {
callItunes: function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
});
Теперь, как и на нашей фабрике, Service, setArtist, getArtist и callItunes будут доступны в любом контроллере, в который мы передаем myProvider. Вот контроллер myProvider (который почти такой же, как наш заводской / сервисный контроллер).
app.controller('myProviderCtrl', function($scope, myProvider){
$scope.data = {};
$scope.updateArtist = function(){
myProvider.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myProvider.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
Как упоминалось ранее, весь смысл создания службы с помощью Provider заключается в возможности изменять некоторые переменные с помощью функции app.config до того, как конечный объект будет передан остальной части приложения. Давайте посмотрим пример этого.
app.config(function(myProviderProvider){
//Providers are the only service you can pass into app.config
myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});
Теперь вы можете видеть, как 'thingFromConfig' является пустой строкой в нашем провайдере, но когда это появится в DOM, это будет "Это предложение было установлено ...".
Все Сервисы являются одиночными ; они создаются один раз за приложение. Они могут быть любого типа , будь то примитив, литерал объекта, функция или даже экземпляр пользовательского типа.
value
, factory
, service
, constant
, И provider
методы все провайдеры. Они учат Инжектора, как создавать Услуги.
Наиболее многословным, но и наиболее полным является рецепт провайдера. В остальных четырех типов рецептов - Value, фабрика, Обслуживание и Constant - это просто синтаксический сахар поверх рецепта поставщика .
Вы должны использовать рецепт провайдера только в том случае, если вы хотите предоставить API для конфигурации всего приложения, которую необходимо выполнить до запуска приложения. Обычно это интересно только для многоразовых сервисов, чье поведение может немного отличаться в разных приложениях.
decorator
.Понимание AngularJS Factory, Сервис и Поставщик
Все они используются для совместного использования одноразовых объектов. Это помогает обмениваться повторно используемым кодом через ваше приложение / различные компоненты / модули.
Из Документов Сервис / Фабрика :
- Ленивый экземпляр - Angular создает экземпляр сервиса / фабрики только тогда, когда от него зависит компонент приложения.
- Singletons - каждый компонент, зависящий от сервиса, получает ссылку на один экземпляр, сгенерированный фабрикой сервисов.
Фабрика - это функция, в которой вы можете манипулировать / добавлять логику перед созданием объекта, после чего возвращается вновь созданный объект.
app.factory('MyFactory', function() {
var serviceObj = {};
//creating an object with methods/functions or variables
serviceObj.myFunction = function() {
//TO DO:
};
//return that object
return serviceObj;
});
Применение
Это может быть просто набор функций, таких как класс. Следовательно, он может быть создан в разных контроллерах, когда вы вводите его в функции контроллера / фабрики / директивы. Он создается только один раз за приложение.
Просто, глядя на сервисы, подумайте о прототипе массива. Служба - это функция, которая создает новый объект, используя ключевое слово «new». Вы можете добавить свойства и функции к объекту службы, используя this
ключевое слово. В отличие от фабрики, он ничего не возвращает (он возвращает объект, который содержит методы / свойства).
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
Применение
Используйте его, когда вам нужно поделиться одним объектом по всему приложению. Например, данные пользователя, прошедшего проверку подлинности, методы / данные для совместного использования, функции служебных программ и т. Д.
Поставщик используется для создания настраиваемого объекта службы. Вы можете настроить параметры сервиса из функции конфигурации. Возвращает значение с помощью $get()
функции. $get
Функция запускается на выполнение на этапе выполнения в угловой.
app.provider('configurableService', function() {
var name = '';
//this method can be be available at configuration time inside app.config.
this.setName = function(newName) {
name = newName;
};
this.$get = function() {
var getName = function() {
return name;
};
return {
getName: getName //exposed object to where it gets injected.
};
};
});
Применение
Когда вам нужно предоставить модульную конфигурацию для вашего сервисного объекта, прежде чем сделать его доступным, например. Предположим, вы хотите установить URL-адрес API на основе вашей среды, например dev
, stage
илиprod
НОТА
Только поставщик будет доступен в фазе конфигурации angular, а сервис и фабрика - нет.
Надеюсь, что это прояснило ваше понимание о фабрике, обслуживании и поставщике .
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
, так что не кажется возможным, верно?
Для меня откровение пришло, когда я понял, что все они работают одинаково: запустив что-то один раз , сохранив полученное значение, а затем обработайте то же самое сохраненное значение, когда на него ссылаются посредством внедрения зависимостей .
Скажем, у нас есть:
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
Разница между тремя заключается в том, что:
a
сохраненное значение приходит от запуска fn
.b
сохраненное значение исходит от new
ing fn
.c
Хранимое значение приходит от первого получения экземпляра с помощью new
ing fn
, а затем запуска $get
метода экземпляра.Это означает, что внутри AngularJS есть что-то вроде объекта кеша, значение которого для каждой инъекции присваивается только один раз, когда они были введены впервые, и где:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
Вот почему мы используем this
в сервисах, а определяем this.$get
в провайдерах.
factory
с. Единственная причина service
существования - это языки, такие как CoffeeScript, TypeScript, ES6 и т. Д., Поэтому вы можете использовать синтаксис их классов. Вам нужны provider
s, только если ваш модуль используется в нескольких приложениях с разными настройками при помощи app.config()
. Если ваш сервис является чисто одноэлементным или способен создавать экземпляры чего-либо, зависит только от вашей реализации.
Сервис против провайдера против фабрики:
Я пытаюсь сделать это простым. Это все о базовой концепции JavaScript.
Прежде всего, давайте поговорим об услугах в AngularJS!
Что такое Сервис: В AngularJS, Сервисэто не что иное, как одиночный объект JavaScript, который может хранить некоторые полезные методы или свойства. Этот одноэлементный объект создается на основе ngApp (приложение Angular) и используется всеми контроллерами в текущем приложении. Когда Angularjs создает объект службы, он регистрирует этот объект службы с уникальным именем службы. Поэтому каждый раз, когда нам нужен экземпляр службы, Angular ищет в реестре это имя службы и возвращает ссылку на объект службы. Таким образом, мы можем вызвать метод, получить доступ к свойствам и т. Д. На объекте службы. У вас может возникнуть вопрос, можете ли вы также поместить свойства, методы в объектную область контроллеров! Так зачем вам сервисный объект? Ответы таковы: сервисы распределяются между несколькими контроллерами. Если вы поместите некоторые свойства / методы в объект области видимости контроллера, он будет доступен только для текущей области видимости.
Таким образом, если существует три области контроллера, пусть это будут controllerA, controllerB и controllerC, все они будут использовать один и тот же экземпляр службы.
<div ng-controller='controllerA'>
<!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
<!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
<!-- controllerC scope -->
</div>
Как создать сервис?
AngularJS предоставляет различные методы для регистрации службы. Здесь мы сосредоточимся на трех методах: фабрика (..), сервис (..), провайдер (..);
Используйте эту ссылку для ссылки на код
Мы можем определить фабричную функцию, как показано ниже.
factory('serviceName',function fnFactory(){ return serviceInstance;})
AngularJS предоставляет метод factory ('serviceName', fnFactory) ', который принимает два параметра, serviceName и функцию JavaScript. Angular создает экземпляр службы, вызывая функцию fnFactory (), например ниже.
var serviceInstace = fnFactory();
Переданная функция может определить объект и вернуть этот объект. AngularJS просто сохраняет эту ссылку на объект в переменную, которая передается в качестве первого аргумента. Все, что возвращается из fnFactory, будет связано с serviceInstance. Вместо того, чтобы возвращать объект, мы также можем возвращать функцию, значения и т. Д. Что бы мы ни возвращали, они будут доступны экземпляру службы.
Пример:
var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
var data={
'firstName':'Tom',
'lastName':' Cruise',
greet: function(){
console.log('hello!' + this.firstName + this.lastName);
}
};
//Now all the properties and methods of data object will be available in our service object
return data;
});
service('serviceName',function fnServiceConstructor(){})
Это еще один способ, мы можем зарегистрировать услугу. Единственное отличие состоит в том, как AngularJS пытается создать экземпляр объекта службы. На этот раз angular использует ключевое слово «new» и вызывает функцию конструктора, как показано ниже.
var serviceInstance = new fnServiceConstructor();
В функции конструктора мы можем использовать ключевое слово this для добавления свойств / методов к объекту службы. пример:
//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
this.firstName ='James';
this.lastName =' Bond';
this.greet = function(){
console.log('My Name is '+ this.firstName + this.lastName);
};
});
Функция Provider () - это еще один способ создания сервисов. Пусть нам интересно создать сервис, который просто отображает какое-то приветственное сообщение пользователю. Но мы также хотим предоставить такую функциональность, чтобы пользователь мог установить собственное приветственное сообщение. В техническом плане мы хотим создавать настраиваемые сервисы. Как мы можем это сделать ? Должен быть способ, чтобы приложение могло передавать свои пользовательские приветственные сообщения, а Angularjs делал бы его доступным для функции фабрики / конструктора, которая создает наш экземпляр сервисов. В таком случае функция provider () выполняет свою работу. используя функцию provider (), мы можем создавать настраиваемые сервисы.
Мы можем создавать настраиваемые сервисы, используя синтаксис провайдера, как указано ниже.
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
1.Provider объект создается с помощью функции конструктора, которую мы определили в нашей функции провайдера.
var serviceProvider = new serviceProviderConstructor();
2. Функция, которую мы передали в app.config (), выполняется. Это называется этапом конфигурации, и здесь у нас есть возможность настроить наш сервис.
configureService(serviceProvider);
3. Наконец, экземпляр службы создается путем вызова $ get метода serviceProvider.
serviceInstance = serviceProvider.$get()
var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
//this function works as constructor function for provider
this.firstName = 'Arnold ';
this.lastName = ' Schwarzenegger' ;
this.greetMessage = ' Welcome, This is default Greeting Message' ;
//adding some method which we can call in app.config() function
this.setGreetMsg = function(msg){
if(msg){
this.greetMessage = msg ;
}
};
//We can also add a method which can change firstName and lastName
this.$get = function(){
var firstName = this.firstName;
var lastName = this.lastName ;
var greetMessage = this.greetMessage;
var data={
greet: function(){
console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
}
};
return data ;
};
});
app.config(
function(providerPatternProvider){
providerPatternProvider.setGreetMsg(' How do you do ?');
}
);
Резюме:
Фабрика использует фабричную функцию, которая возвращает экземпляр службы. serviceInstance = fnFactory ();
Сервис использует функцию конструктора, и Angular вызывает эту функцию конструктора, используя ключевое слово «new» для создания экземпляра сервиса. serviceInstance = new fnServiceConstructor ();
Provider определяет функцию providerConstructor, эта функция providerConstructor определяет фабричную функцию $ get . Angular вызывает $ get () для создания объекта службы. Синтаксис провайдера имеет дополнительное преимущество в настройке объекта службы перед его созданием. serviceInstance = $ get ();
Как правильно отметили несколько человек, фабрика, поставщик, сервис и даже значение и константа являются версиями одного и того же. Вы можете разбить более общее provider
на всех из них. Вот так:
Вот статья, из которой это изображение:
Вы даете AngularJS функцию, AngularJS будет кешировать и вводить возвращаемое значение, когда запрашивается фабрика.
Пример:
app.factory('factory', function() {
var name = '';
// Return value **is** the object that will be injected
return {
name: name;
}
})
Применение:
app.controller('ctrl', function($scope, factory) {
$scope.name = factory.name;
});
Вы даете AngularJS функцию, AngularJS вызовет new, чтобы создать ее экземпляр. Это экземпляр, который создает AngularJS, который будет кэшироваться и вставляться при запросе сервиса. Поскольку new использовался для создания экземпляра службы, ключевое слово this является действительным и относится к экземпляру.
Пример:
app.service('service', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.getName = function() {
return name;
}
});
Применение:
app.controller('ctrl', function($scope, service) {
$scope.name = service.getName();
});
Вы даете AngularJS функцию, а AngularJS будет вызывать ее $get
функцию. Это возвращаемое значение из $get
функции, которая будет кэшироваться и вставляться при запросе службы.
Провайдеры позволяют вам настроить провайдера до того, как AngularJS $get
вызовет метод, чтобы получить инъекцию.
Пример:
app.provider('provider', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.$get = function() {
return {
name: name
}
}
})
Использование (как инъекция в контроллере)
app.controller('ctrl', function($scope, provider) {
$scope.name = provider.name;
});
Использование (настройка провайдера перед $get
вызовом для создания инъекционного)
app.config(function(providerProvider) {
providerProvider.setName('John');
});
Я заметил кое-что интересное, играя с провайдерами.
Видимость инъекционных препаратов различна для поставщиков, чем для служб и предприятий. Если вы объявите AngularJS «константой» (например, myApp.constant('a', 'Robert');
), вы можете внедрить его в службы, фабрики и поставщиков.
Но если вы объявите AngularJS «значение» (например,. myApp.value('b', {name: 'Jones'});
), Вы можете внедрить его в службы и фабрики, но НЕ в функцию создания провайдера. Однако вы можете добавить его в $get
функцию, определенную для вашего провайдера. Это упоминается в документации AngularJS, но это легко пропустить. Вы можете найти его на странице% provide в разделах о методах value и constant.
<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>
Это очень запутанная часть для новичка, и я попытался объяснить это простыми словами
Служба AngularJS: используется для совместного использования служебных функций со ссылкой на службу в контроллере. Служба является одноэлементной по своей природе, поэтому для одного сервиса в браузере создается только один экземпляр, и одна и та же ссылка используется на всей странице.
В сервисе мы создаем имена функций как свойства этого объекта.
AngularJS Factory: назначение Factory также совпадает с Service, однако в этом случае мы создаем новый объект и добавляем функции в качестве свойств этого объекта, а в конце возвращаем этот объект.
Поставщик AngularJS: цель этого снова та же, однако поставщик предоставляет вывод своей функции $ get.
Определение и использование Сервиса, Фабрики и Поставщика объясняются по адресу http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider.
Для меня лучший и самый простой способ понять разницу это:
var service, factory;
service = factory = function(injection) {}
Как AngularJS создает конкретные компоненты (упрощенно):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
Таким образом, для службы то, что становится компонентом AngularJS, является экземпляром объекта класса, который представлен функцией объявления службы. Для фабрики это результат, возвращаемый функцией объявления фабрики. Фабрика может вести себя так же, как сервис:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
Самый простой способ мышления следующий:
Пример фабричного «класса» приведен в комментариях, а также о разнице поставщиков.
new MyService()
или что-то :)
Мои разъяснения по этому вопросу:
В основном все упомянутые типы (сервис, фабрика, поставщик и т. Д.) Просто создают и настраивают глобальные переменные (которые, конечно, являются глобальными для всего приложения), как это делали устаревшие глобальные переменные.
Хотя глобальные переменные не рекомендуются, реальное использование этих глобальных переменных заключается в обеспечении внедрения зависимостей путем передачи переменной соответствующему контроллеру.
Существует много уровней сложности при создании значений для «глобальных переменных»:
app.config
.
app.config
файл, и эта функция $ .get ведет себя так же, как фабрика выше, тем, что его возвращаемое значение используется для инициализации «глобальных» переменных. Мое понимание очень просто ниже.
Фабрика: вы просто создаете объект внутри фабрики и возвращаете его.
Обслуживание:
У вас просто есть стандартная функция, которая использует это ключевое слово для определения функции.
Поставщик:
Существует $get
объект, который вы определяете, и его можно использовать для получения объекта, который возвращает данные.
Резюме из угловых документов :
Лучшие ответы от SO:
https://stackoverflow.com/a/26924234/165673 (<- ХОРОШО)
https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673
Все хорошие ответы уже. Я хотел бы добавить еще несколько пунктов на Сервис и Фабрика . Вместе с разницей между сервисом / фабрикой. И можно также иметь такие вопросы, как:
Давайте начнем с разницы между обслуживанием и фабрикой:
Оба являются синглетонами : всякий раз, когда Angular находит их как зависимость в первый раз, он создает один экземпляр сервиса / фабрики. Как только экземпляр создан, тот же экземпляр используется навсегда.
Может использоваться для моделирования объекта с поведением : у них могут быть методы, внутренние переменные состояния и т. Д. Хотя способ написания этого кода будет отличаться.
Сервисы:
Сервис - это функция конструктора, и Angular создаст его экземпляр, вызвав new yourServiceName()
. Это означает пару вещей.
this
.new yourServiceName(
), он получит this
объект со всеми свойствами, которые вы на него наделили.Пример примера:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
Когда Angular внедряет этот
MyService
сервис в контроллер, который зависит от него, этот контроллер получит объектMyService
, для которого он может вызывать функции, например MyService.aServiceMethod ().
Будьте осторожны сthis
:
Поскольку созданный сервис является объектом, методы внутри него могут ссылаться на него при вызове:
angular.service('ScoreKeeper', function($http) {
this.score = 0;
this.getScore = function() {
return this.score;
};
this.setScore = function(newScore) {
this.score = newScore;
};
this.addOne = function() {
this.score++;
};
});
У вас может возникнуть соблазн вызвать ScoreKeeper.setScore
цепочку обещаний, например, если вы инициализировали счет, взяв его с сервера: $http.get('/score').then(ScoreKeeper.setScore).
проблема в том, что ScoreKeeper.setScore
он будет вызван с this
привязкой к, null
и вы получите ошибки. Лучший способ был бы $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))
. Если вы решите использовать это в своих методах обслуживания или нет, будьте осторожны, как вы их называете.
Возврат значения изService
:
Из-за того, как работают конструкторы JavaScript, если вы возвращаете комплексное значение (i.e., an Object)
из constructor
функции, вызывающая сторона получит этот объект вместо этого экземпляра.
Это означает, что вы можете скопировать и вставить заводской пример снизу, заменить factory
на service
, и он будет работать:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
Поэтому, когда Angular создает ваш сервис с новым MyService (), он получает этот объект API вместо экземпляра MyService.
Это поведение для любых сложных значений (объектов, функций), но не для примитивных типов.
Заводы:
Фабрика - это простая старая функция, которая возвращает значение. Возвращаемое значение - это то, что вводится в вещи, которые зависят от фабрики. Типичный шаблон фабрики в Angular - возвращать объект с функциями в качестве свойств, например так:
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
Введенное значение для фабричной зависимости - это возвращаемое фабрикой значение, и оно не обязательно должно быть объектом. Это может быть функцией
Ответы на вопросы 1 и 2 выше:
По большей части, просто используйте фабрики для всего. Их поведение легче понять. Нет никакого выбора, возвращать ли значение или нет, и, кроме того, нет ошибок, если вы поступите неправильно.
Однако я все еще называю их «услугами», когда говорю о внедрении их как зависимостей.
Поведение Service / Factory очень похоже, и некоторые люди скажут, что любой из них в порядке. Это несколько верно, но мне легче следовать советам руководства по стилю Джона Папы и просто придерживаться заводов. **
Дополнительным разъяснением является то, что фабрики могут создавать функции / примитивы, а службы - нет. Проверьте это jsFiddle на основе Epokk's: http://jsfiddle.net/skeller88/PxdSP/1351/ .
Фабрика возвращает функцию, которая может быть вызвана:
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
Фабрика также может вернуть объект с методом, который может быть вызван:
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
Служба возвращает объект с методом, который может быть вызван:
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
Для получения дополнительной информации см. Сообщение, которое я написал о разнице: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/
Уже есть хорошие ответы, но я просто хочу поделиться этим.
Прежде всего: Provider - это способ / рецепт для создания service
(одноэлементного объекта), который должен быть введен $ инжектором (как AngulaJS использует шаблон IoC).
И Value, Factory, Service и Constant (4 способа) - синтаксический сахар по сравнению с Provider way / recepie.
Там есть Service vs Factory
часть была покрыта:
https://www.youtube.com/watch?v=BLzNCkPn3ao
Сервис - это все о new
ключевом слове, которое, как мы знаем, делает 4 вещи:
prototype
объектомcontext
кthis
this
А Factory - это все о Factory Pattern - содержит функции, которые возвращают объекты, подобные этой службе.
И это простое / короткое видео: охватывает также провайдера : https://www.youtube.com/watch?v=HvTZbQ_hUZY (там, на котором вы видите, видно, как они идут от фабрики к провайдеру)
Рецепт провайдера используется в основном в конфигурации приложения до того, как приложение полностью запустится / инициализируется.
После прочтения всех этих постов это создало больше путаницы для меня .. Но все же все это является полезной информацией .. наконец я нашел следующую таблицу, которая даст информацию с простым сравнением
И для начинающего понять: - Это может не исправить вариант использования, но на высоком уровне это то, что сценарий использования для этих трех.
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
Для базовых сценариев фабрика и сервис ведут себя одинаково.
Вот пример кода, который я придумал как шаблон кода для фабрики объектов в AngularjS. Я использовал Car / CarFactory в качестве примера для иллюстрации. Делает для простой реализации кода в контроллере.
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
Вот более простой пример. Я использую несколько сторонних библиотек, которые ожидают объект «Положение», демонстрирующий широту и долготу, но через различные свойства объекта. Я не хотел взламывать код вендора, поэтому я настроил объекты «Положение», которые я передавал.
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
;
Используя в качестве ссылки эту страницу и документацию (которая, кажется, значительно улучшилась с тех пор, как я в последний раз смотрел), я собрал следующую (-ish) демонстрацию мира, в которой используются 4 из 5 вариантов провайдера; Значение, Постоянный, Заводской и полномасштабный Провайдер.
HTML:
<div ng-controller="mainCtrl as main">
<h1>{{main.title}}*</h1>
<h2>{{main.strapline}}</h2>
<p>Earn {{main.earn}} per click</p>
<p>You've earned {{main.earned}} by clicking!</p>
<button ng-click="main.handleClick()">Click me to earn</button>
<small>* Not actual money</small>
</div>
приложение
var app = angular.module('angularProviders', []);
// A CONSTANT is not going to change
app.constant('range', 100);
// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');
// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
// Get a random number within the range defined in our CONSTANT
return Math.random() * range;
});
// A PROVIDER, must return a custom type which implements the functionality
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will
// instantiate and return.
var Money = function(locale) {
// Depending on locale string set during config phase, we'll
// use different symbols and positioning for any values we
// need to display as currency
this.settings = {
uk: {
front: true,
currency: '£',
thousand: ',',
decimal: '.'
},
eu: {
front: false,
currency: '€',
thousand: '.',
decimal: ','
}
};
this.locale = locale;
};
// Return a monetary value with currency symbol and placement, and decimal
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {
var settings = this.settings[this.locale],
decimalIndex, converted;
converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);
decimalIndex = converted.length - 3;
converted = converted.substr(0, decimalIndex) +
settings.decimal +
converted.substr(decimalIndex + 1);
converted = settings.front ?
settings.currency + converted :
converted + settings.currency;
return converted;
};
// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};
// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {
var locale;
// Function called by the config to set up the provider
this.setLocale = function(value) {
locale = value;
};
// All providers need to implement a $get method which returns
// an instance of the custom class which constitutes the service
this.$get = function moneyFactory() {
return new Money(locale);
};
});
// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
moneyProvider.setLocale('uk');
//moneyProvider.setLocale('eu');
}]);
// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {
// Plain old VALUE(s)
this.title = title;
this.strapline = strapline;
this.count = 0;
// Compute values using our money provider
this.earn = money.convertValue(random); // random is computed @ runtime
this.earned = money.convertValue(0);
this.handleClick = function() {
this.count ++;
this.earned = money.convertValue(random * this.count);
};
});
Рабочая демка .
Этот ответ обратиться к теме / вопросу
ИЛИ
в основном то, что происходит
Когда вы сделаете factory()
это наборами вы при function
условии , во втором аргументе провайдера $get
и вернуть его ( provider(name, {$get:factoryFn })
), все , что вы получаете, provider
но нет никакой собственности / метода, кроме$get
того , чтоprovider
(значит, вы не можете настроить это)
Исходный код фабрики
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
Когда service()
вы возвращаете его, вы предоставляете factory () функцию, function
которая внедряет constructor
(возвращает экземпляр конструктора, предоставленного вами в вашем сервисе) и возвращает его
Исходный код сервиса
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
Таким образом, в основном в обоих случаях вы в конечном итоге получаете $ провайдера, настроенного на вашу функцию, которую вы предоставили, но вы можете дать что-то большее, чем $ get, как вы могли изначально предоставить в provider () для блока конфигурации
Я знаю много отличных ответов, но я должен поделиться своим опытом использования
1. service
для большинства случаев по умолчанию
2. factory
используется для создания службы для этого конкретного экземпляра
// factory.js ////////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];
function xFactoryImp($http) {
var fac = function (params) {
this._params = params; // used for query params
};
fac.prototype.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
return fac;
}
})();
// service.js //////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];
function xServiceImp($http) {
this._params = {'model': 'account','mode': 'list'};
this.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
}
})();
и используя:
controller: ['xFactory', 'xService', function(xFactory, xService){
// books = new instance of xFactory for query 'book' model
var books = new xFactory({'model': 'book', 'mode': 'list'});
// accounts = new instance of xFactory for query 'accounts' model
var accounts = new xFactory({'model': 'account', 'mode': 'list'});
// accounts2 = accounts variable
var accounts2 = xService;
...
Немного опоздал на вечеринку. Но я подумал, что это более полезно для тех, кто хотел бы узнать (или иметь ясность) о разработке пользовательских служб Angular JS с использованием методологий фабрики, сервиса и провайдера.
Я наткнулся на это видео, в котором четко объясняются методологии фабрики, сервиса и провайдера для разработки пользовательских сервисов AngularJS:
https://www.youtube.com/watch?v=oUXku28ex-M
Исходный код: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
Код, размещенный здесь, скопирован прямо из вышеуказанного источника, чтобы помочь читателям.
Код для настраиваемой службы, основанной на фабрике, выглядит следующим образом (который используется как для синхронизации, так и для асинхронной версии, а также для вызова службы http):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
function($scope, calcFactory) {
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function() {
//$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
$scope.sum = r;
});
};
}
]);
app.factory('calcFactory', ['$http', '$log',
function($http, $log) {
$log.log("instantiating calcFactory..");
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb) { //using http service
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp) {
$log.log(resp.data);
cb(resp.data);
}, function(resp) {
$log.error("ERROR occurred");
});
};
return oCalcService;
}
]);
Код для «сервисной» методологии для пользовательских сервисов (это очень похоже на «фабрику», но отличается от синтаксической точки зрения):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.service('calcService', ['$http', '$log', function($http, $log){
$log.log("instantiating calcService..");
//this.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//this.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
this.getSum = function(a, b, cb){
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
}]);
Код для методологии «провайдера» для пользовательских сервисов (это необходимо, если вы хотите разработать сервис, который можно настроить):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.provider('calcService', function(){
var baseUrl = '';
this.config = function(url){
baseUrl = url;
};
this.$get = ['$log', '$http', function($log, $http){
$log.log("instantiating calcService...")
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb){
$http({
url: baseUrl + '/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
return oCalcService;
}];
});
app.config(['calcServiceProvider', function(calcServiceProvider){
calcServiceProvider.config("http://localhost:4467");
}]);
Наконец, пользовательский интерфейс, который работает с любым из вышеперечисленных сервисов:
<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>
Просто чтобы прояснить ситуацию, из источника AngularJS вы можете увидеть, что сервис просто вызывает фабричную функцию, которая, в свою очередь, вызывает функцию провайдера:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
Давайте обсудим три способа простой обработки бизнес-логики в AngularJS: ( Вдохновленный курсом Яакова Coursera AngularJS )
СЕРВИС :
Синтаксис:
app.js
var app = angular.module('ServiceExample',[]);
var serviceExampleController =
app.controller('ServiceExampleController', ServiceExampleController);
var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
function ServiceExampleController(NameOfTheService){
serviceExampleController = this;
serviceExampleController.data = NameOfTheService.getSomeData();
}
function NameOfTheService(){
nameOfTheService = this;
nameOfTheService.data = "Some Data";
nameOfTheService.getSomeData = function(){
return nameOfTheService.data;
}
}
index.html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
Особенности сервиса:
ФАБРИКА
Сначала давайте посмотрим на синтаксис:
app.js :
var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
//first implementation where it returns a function
function NameOfTheFactoryOne(){
var factory = function(){
return new SomeService();
}
return factory;
}
//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
var factory = {
getSomeService : function(){
return new SomeService();
}
};
return factory;
}
Теперь с помощью двух выше в контроллере:
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
Особенности Фабрики:
.service()
Метод является заводом , который всегда производит один и тот же тип сервиса, который одноэлементен, и без какого - либо простого способа настроить его поведение. Этот .service()
метод обычно используется в качестве ярлыка для чего-то, что не требует какой-либо настройки.ПРОВАЙДЕР
Давайте снова посмотрим на синтаксис первым:
angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional
Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
ServiceProvider.defaults.maxItems = 10; //some default value
}
ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
//some methods
}
function ServiceProvider() {
var provider = this;
provider.defaults = {
maxItems: 10
};
provider.$get = function () {
var someList = new someListService(provider.defaults.maxItems);
return someList;
};
}
}
Особенности провайдера:
.service
или .factory
методы.$get
функция, которая напрямую связана с экземпляром провайдера. Эта функция является заводской функцией. Другими словами, это так же , как тот , который мы используем , чтобы обеспечить к .factory
методу. В этой функции мы создаем наш собственный сервис. Это $get
свойство, то есть функция, делает провайдера провайдером . AngularJS ожидает, что у провайдера будет свойство $ get, значением которого является функция, которую Angular будет рассматривать как фабричную функцию. Но что делает всю эту настройку поставщика очень особенной, так это то, что мы можем предоставить некоторый config
объект внутри поставщика услуг, и это обычно идет со значениями по умолчанию, которые мы можем позже перезаписать на шаге, где мы можем настроить все приложение.Фабрика: фабрика, на которой вы фактически создаете объект внутри фабрики и возвращаете его.
сервис: сервис, у вас просто есть стандартная функция, которая использует ключевое слово this для определения функции.
провайдер: в качестве провайдера вы определяете $ get, и его можно использовать для получения объекта, который возвращает данные.
По сути, Поставщик, Завод и Сервис - все это Услуги. Фабрика - это особый случай службы, когда все, что вам нужно, это функция $ get (), позволяющая писать ее с меньшим количеством кода.
Основными различиями между Сервисами, Фабриками и Поставщиками являются их сложности. Службы являются самой простой формой, фабрики немного более устойчивы, а провайдеры настраиваются во время выполнения.
Вот краткое изложение того, когда использовать каждый:
Фабрика : предоставляемое вами значение должно быть рассчитано на основе других данных.
Сервис : вы возвращаете объект с методами.
Поставщик : вы хотите иметь возможность настроить на этапе настройки объект, который будет создан до его создания. Используйте поставщика в основном в конфигурации приложения, прежде чем приложение будет полностью инициализировано.
1.Услуги - это одноэлементные объекты, которые создаются при необходимости и никогда не очищаются до конца жизненного цикла приложения (когда браузер закрыт). Контроллеры уничтожаются и очищаются, когда они больше не нужны.
2. Самый простой способ создать сервис - использовать метод factory (). Метод factory () позволяет нам определять службу, возвращая объект, который содержит функции службы и данные службы. Функция определения сервиса - это место, где мы размещаем наши инъекционные сервисы, такие как $ http и $ q. Пример:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
Используя factory () в нашем приложении
В нашем приложении легко использовать фабрику, поскольку мы можем просто внедрить ее туда, где она нам нужна во время выполнения.
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});
Синтаксический сахар - это разница . Нужен только провайдер. Или, другими словами, реальным углом является только поставщик, все остальные являются производными (для уменьшения кода). Существует также простая версия, называемая Value (), которая возвращает только значение, без вычисления или функции. Четное значение получено от поставщика!
Так почему такие сложности, почему мы не можем просто использовать провайдера и забыть обо всем остальном? Предполагается, что это поможет нам легче писать код и лучше общаться. И ответ будет сложнее, чем сложнее он становится, тем лучше будет продажа фреймворка.
Угловая инъекция дает нам первый намек в достижении этого заключения.
«$ injector используется для извлечения экземпляров объекта, как определено поставщиком », не службой, не фабрикой, а провайдером.
И лучшим ответом было бы следующее: «Служба Angular создается фабрикой сервисов. Эти фабрики сервисов являются функциями, которые, в свою очередь, создаются поставщиком услуг. Поставщики услуг являются функциями конструктора. При реализации они должны содержать свойство называется $ get, который содержит функцию фабрики сервиса. "
Так что мастер провайдер и инжектор и все встанет на свои места :). И в Typescript становится интересным, когда $ get может быть реализован в провайдере путем наследования от IServiceProvider.