30 Вопрос: AngularJS: Сервис против провайдера против фабрики

вопрос создан в Fri, Nov 25, 2016 12:00 AM

Каковы различия между Service, Provider и Factory в AngularJS?

    
3271
  1. Я обнаружил, что все угловые термины были пугающими для начинающих. Мы начали с этой таблицы, которую нашим программистам было немного легче понять, изучая Angular demisx.github.io/angularjs/2014/09/14/… . Надеюсь, это тоже поможет вашей команде.
    2014-09-16 17: 07: 00Z
  2. По моему мнению, лучший способ понять разницу - это использовать собственную документацию Angular: docs.angularjs.org/guide/providers это очень хорошо объяснено и использует необычный пример, чтобы помочь вам понять это.
    2015-05-12 14: 28: 05Z
  3. @ Blaise Спасибо! Согласно моему комментарию в посте, я умышленно исключил его, поскольку 99% случаев использования из моего опыта могут быть успешно обработаны с помощью service.factory. Не хотел усложнять эту тему дальше.
    2016-01-13 01: 22: 43Z
  4. Я считаю, что это обсуждение также очень полезно stackoverflow.com/questions/18939709/…
    2016-02-18 13: 03: 19Z
  5. Вот несколько хороших ответов о том, как работают services, factories и providers.
    2016-10-18 09: 35: 05Z
30 ответов                              30                         

Из списка рассылки AngularJS я получил потрясающую тему , в которой рассказывается о сервисе и фабрике против провайдера и их использование инъекций. Составление ответов:

Услуги

Синтаксис: module.service( 'serviceName', function );
Результат: при объявлении serviceName в качестве вводимого аргумента вам будет предоставлен экземпляр функции. Другими словами new FunctionYouPassedToService().

Заводы

Синтаксис: module.factory( 'factoryName', function );
Результат: при объявлении factoryName в качестве вводимого аргумента вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory .

Провайдеры

Синтаксис: module.provider( 'providerName', function );
Результат: при объявлении providerName в качестве вводимого аргумента вам будет предоставлен (new ProviderFunction()).$get(). Функция конструктора создается перед вызовом метода $get - ProviderFunction - это ссылка на функцию, переданную в module.provider.

Поставщики имеют преимущество в том, что их можно настраивать на этапе настройки модуля.

См. здесь для предоставленного кода.

Вот большое дальнейшее объяснение Миско:

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

Как сторона нOte, 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;
  });
};
    
2850
2016-01-31 23: 34: 07Z
  1. См. также stackoverflow.com/a/13763886/215945 где обсуждаются различия между сервисом и фабрикой.
    2013-03-27 18: 10: 49Z
  2. В редактировании 611 я добавил использование угловых констант и значений. Чтобы продемонстрировать отличия друг от друга, уже показано. jsbin.com/ohamub/611/edit
    2013-07-08 15: 30: 59Z
  3. Хотя служба вызывается путем создания экземпляра функции. Фактически он создается только один раз для каждого инжектора, что делает его похожим на синглтон. docs.angularjs.org/руководство /dev_guide.services.creating_services
    2013-12-15 06: 17: 27Z
  4. Этот пример может быть невероятным, если использовать четкий практический пример. Я заблудился, пытаясь понять, в чем смысл таких вещей, как toEqual и greeter.Greet. Почему бы не использовать что-то более реальное и подходящее?
    2014-08-06 18: 35: 52Z
  5. Использование функции wait () - плохой выбор для объяснения чего-либо. В следующий раз используйте код реального мира.
    2014-10-03 20: 23: 04Z

Демонстрация JS Fiddle

Пример "Hello world" с 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>
    
807
2016-03-09 05: 55: 15Z
  1. Не меняет ли this контекст в функции $get? - вы больше не ссылаетесь на созданного провайдера в этой функции.
    2013-10-23 19: 17: 51Z
  2. @ Nate: this на самом деле не меняет контекст, потому что вызывается new Provider(). $get (), где Provider - это функция, передаваемая в app.provider. То есть $get() вызывается в качестве метода на построенном Provider, поэтому this будет ссылаться на Provider, как показывает пример.
    2013-10-28 15: 50: 59Z
  3. @ Брэндон О, ладно, тогда все в порядке. Смущает на первый взгляд - спасибо за разъяснения!
    2013-10-28 16: 03: 47Z
  4. Почему я получаю Unknown provider: helloWorldProvider <- helloWorld при локальном запуске? Комментируя это, та же ошибка для двух других примеров. Есть ли какая-то скрытая конфигурация провайдера? (Angular 1.0.8) - Найдено: stackoverflow.com/questions/12339272 /...
    2013-11-05 09: 13: 06Z
  5. Является причиной, по которой @Antoine получает ошибку «Неизвестный предоставить: helloWorldProvider», поскольку в вашем коде .config вы используете «helloWorldProvider», но когда вы определяете провайдера в myApp.provider ('helloWorld', function ()), вы используете "helloWorld"? Другими словами, как Angular узнает, что вы обращаетесь к провайдеру helloWorld? Благодаря
    2014-05-03 06: 48: 43Z

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

Теперь любые свойства, которые мы прикрепляем к «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;
});

Здесь вы заметите, что мы не привязываем эти переменные /функцию к «сервису». Мы просто создаем их, чтобы потом их использовать или изменить.

  • baseUrl - это базовый URL, который требуется для API iTunes
  • _artist - это художник, которого мы хотим найти
  • _finalUrl - это окончательный и полностью созданный URL-адрес, по которому мы будем звонить в iTunes
  • makeUrl - это функция, которая создает и возвращает наш удобный для URL URL.

Теперь, когда наши вспомогательные /закрытые переменные и функции созданы, давайте добавим некоторые свойства к объекту «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», давайте рассмотрим некоторые JavaОсновы сценариев, которые в конечном итоге помогут нам понять природу Сервиса.

Чтобы действительно увидеть изменения, которые происходят, когда вы вызываете функцию с ключевым словом «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’

Теперь давайте посмотрим, что на самом деле происходит, когда вы используете новое ключевое слово в 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». Объединяя эти знания с нашими примерами выше, вы должны теперь признать, что вы будете привязывать свои свойства и методы непосредственно к «этому», которое затем будет возвращено из самой Службы. Давайте посмотрим на это в действии.

В отличие от того, что мы изначально делали с примером 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;
  }
});

Теперь мы прикрепим все наши методы, которые будут доступны в нашем контроллере, к «этому».

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

* Опять же, если какая-то часть приведенного выше кода вводит в заблуждение, ознакомьтесь с разделом Factory, где я объясняюШляпа это все делает больше деталей.

Вы можете думать о провайдерах как о трех разделах. Первый раздел - это «закрытые» переменные /функции, которые будут изменены /установлены позже (показано выше). Второй раздел - это переменные /функции, которые будут доступны в вашей функции 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, это будет "Это предложение было установлено ...".

    
639
2017-01-05 15: 23: 07Z
  1. Единственная часть, которая отсутствует в этой превосходной статье, - это относительные преимущества использования сервиса над фабрикой; что ясно объясняется в принятом ответе Лиора
    2014-10-08 04: 46: 55Z
  2. FWIW (возможно, не очень), вот блоггер, который сталкивается с проблемой Angular, и ему не нравится providerProvider codeofrob.com/entries/you-have-ruined-javascript.html
    2015-08-06 21: 08: 34Z
  3. Изюминка "гуру JavaScript" была хитрой. : D Думаю, этот ответ очень многое прояснит. Великолепно написано.
    2017-01-11 08: 23: 02Z
  4. Вашему TLDR требуется TLDR.
    2017-01-19 13: 48: 21Z
  5. @ JensB tl; dr - Learn React.
    2017-01-21 02: 02: 39Z

Все сервисы являются одиночками ; они создаются один раз за приложение. Они могут быть любого типа , будь то примитив, литерал объекта, функция или даже экземпляр пользовательского типа.

Методы value, factory, service, constant и provider являются поставщиками. Они учат Инжектора создавать экземпляры Сервисов.

  

Наиболее многословным, но и наиболее полным из них является поставщик   рецепт. оставшиеся четыре типа рецептов - Value, Factory, Service и   Константа - - это просто синтаксический сахар поверх рецепта поставщика .

р>

  • Value Recipe - это простейший случай, когда вы сами создаете экземпляр Службы и предоставляете значение для инжектора.
  • Заводской рецепт дает Injector заводскую функцию, которую он вызывает, когда ему нужно создать экземпляр службы. При вызове фабричная функция создает и возвращает экземпляр службы. Зависимости SСлужба вставляется в качестве аргументов функций. Таким образом, использование этого рецепта добавляет следующие способности:
    • Возможность использовать другие сервисы (есть зависимости)
    • Инициализация службы
    • отложенная /отложенная инициализация
  • Сервисный рецепт практически совпадает с рецептом Factory, но здесь Injector вызывает конструктор с оператором new вместо фабричной функции.
  • Рецепт провайдера обычно излишне . Он добавляет еще один уровень косвенности, позволяя настроить создание фабрики.
      

    Вы должны использовать рецепт провайдера только тогда, когда вы хотите представить API   для конфигурации всего приложения, которая должна быть сделана до   Приложение запускается. Это обычно интересно только для многоразового использования   услуги, поведение которых может нуждаться в незначительном   приложения.

  •   
  • Рецепт Константа аналогичен рецепту Value, за исключением того, что он позволяет вам определять службы, доступные на этапе config . Раньше, чем сервисы, созданные с использованием рецепта Value. В отличие от значений, они не могут быть оформлены с использованием decorator.
  •   
  См. документацию поставщика .     
509
2014-12-13 17: 01: 30Z
  1. То есть сервис и фабрика по сути одинаковы? Использование одного из других обеспечивает ничего, кроме альтернативного синтаксиса?
    2015-02-21 21: 36: 06Z
  2. @ Мэтт, да, сервис - это лаконичный способ, когда у вас уже есть собственная функция, которую вы хотите представить как сервис. Из документов: myApp.factory ('unicornLauncher', ["apiToken", function (apiToken) {вернуть новый UnicornLauncher (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
    2015-02-22 18: 39: 42Z
  3. @ joshperry Как новичок, я некоторое время гуглял разницу между сервисом и фабрикой. Я согласен, что это лучший ответ! Я бы понял службу как класс службы (например, класс кодировщика /декодера), который может иметь некоторые частные свойства. А фабрика предоставляет набор вспомогательных методов без сохранения состояния.
    2015-03-14 15: 16: 28Z
  4. Примеры Yaa в других ответах, приведенных выше, не очень четко объясняют основное различие между ч /б услугами и поставщиками, которое и вводится в момент создания этих рецептов.
    2015-04-23 07: 43: 04Z

    Общие сведения о AngularJS Factory, Service и Provider

    Все они используются для обмена одноразовыми объектами многократного использования. Это помогает обмениваться повторно используемым кодом между вашим приложением /различными компонентами /модулями.

      

    Из документов Сервис /Фабрика :

         
    • Ленивый экземпляр . 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:
        };
    });
    

    Использование

    Используйте его, когда вам нужно совместно использовать один объект во всем приложении. Например, данные пользователя, прошедшего проверку подлинности, методы /данные для совместного использования, служебные функции и т. Д.

    Provider

    Поставщик используется для создания настраиваемого объекта службы. Вы можете настроить параметры сервиса из функции конфигурации. Возвращает значение с помощью функции $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, в то время как   сервис & фабрики нет.

    Надеюсь, это прояснило ваше понимание Фабрики, Сервиса и Поставщика .

        
    222
    2016-01-31 16: 53: 52Z
    1. Что бы я сделал, если бы мне хотелось иметь службу с определенным интерфейсом, но иметь две разные реализации и внедрять каждую в контроллер, но привязывать к различным состояниям с помощью пользовательского интерфейса -router? например делать удаленные вызовы в одном состоянии, но вместо этого записывать в локальное хранилище. Документы провайдера говорят, что нужно использовать only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications, так что звучит невозможно, верно?
      2015-09-09 00: 37: 11Z

    Для меня откровение пришло, когда я понял, что все они работают одинаково: запустив что-то один раз , сохранив полученное значение, а затем выкашливая это же сохраненное значение при ссылке через внедрение зависимостей .

    Скажем, у нас есть:

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

    Разница между этими тремя заключается в том, что:

    1.  Сохраненное значение a получается при запуске fn.
    2.  b хранится в new и fn.
    3.  Хранимое значение c приходит от получения экземпляра сначала по new до fn, а затем от запуска метода экземпляра $get.

    Это означает, что внутри AngularJS есть что-то вроде объекта кэша, значение которого для каждой инъекции присваивается только один раз, когда они были введены впервые, и где:

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

    Именно поэтому мы используем this в сервисах и определяем this.$get в провайдерах.

        
    191
    2014-12-13 18: 14: 28Z
    1. Мне также больше всего нравится этот ответ. Смысл всех их заключается в предоставлении доступа к объекту при необходимости через DI. Обычно у вас все хорошо с factory с. Единственная причина, по которой существуют service, - это такие языки, как CoffeeScript, TypeScript, ES6 и т. Д., Поэтому вы можете использовать синтаксис их классов. Вам нужно provider с, только если ваш модуль используется в нескольких приложениях с различными настройками с помощью app.config(). Если ваш сервис является чисто одноэлементным или способен создавать экземпляры чего-либо, зависит только от вашей реализации.
      2016-04-07 08: 12: 33Z

    Сервис против провайдера против фабрики:

    Я пытаюсь сделать это простым. Все дело в базовой концепции 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 ?');
      }
    );
    

    Рабочая демонстрация

    Резюме:

    Factory использует фабричную функцию, которая возвращает экземпляр службы. serviceInstance = fnFactory ();

    Сервис использует функцию конструктора, и Angular вызывает эту функцию конструктора, используя ключевое слово 'new' для создания экземпляра сервиса. serviceInstance = new fnServiceConstructor ();

    Provider определяет функцию providerConstructor, эта функция providerConstructor определяет фабричную функцию $get . Angular вызывает $get () для создания объекта службы. Синтаксис провайдера имеет дополнительное преимущество в настройке объекта службы перед его созданием. serviceInstance = $get ();

        
    135
    2016-04-08 14: 06: 00Z

    Как правильно отметили несколько человек, фабрика, поставщик, сервис и даже значение и константа являются версиями одного и того же. Вы можете разбить более общие provider на всех из них. Вот так:

     введите описание изображения здесь р>

    Вот статья, из которой это изображение:

    http: //www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/ р>     

    84
    2017-04-19 13: 38: 06Z

    Завод

    Вы предоставляете 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();
    });
    

    Provider

    Вы предоставляете 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');
    });
    
        
    62
    2014-12-13 17: 19: 28Z

    Я заметил кое-что интересное, играя с провайдерами.

    Видимость инъекционных препаратов различна для поставщиков, чем для служб и предприятий. Если вы объявите AngularJS «константой» (например, myApp.constant('a', 'Robert');), вы можете внедрить его в службы, фабрики и поставщиков.

    Но если вы объявляете AngularJS «значение» (например, myApp.value('b', {name: 'Jones'});), вы можете внедрить его в службы и фабрики, но НЕ в функцию создания провайдера. Однако вы можете добавить его в функцию $get, которую вы определили для своего провайдера. Это упоминается в документации AngularJS, но это легко пропустить. Вы можете найти его на странице% provide в разделах о методах value и constant.

    http://jsfiddle.net/R2Frv/1/

     
    <div ng-app="MyAppName">
        <div ng-controller="MyCtrl">
            <p>from Service: {{servGreet}}</p>
            <p>from Provider: {{provGreet}}</p>
        </div>
    </div>
    <script>
        var myApp = angular.module('MyAppName', []);
    
        myApp.constant('a', 'Robert');
        myApp.value('b', {name: 'Jones'});
    
        myApp.service('greetService', function(a,b) {
            this.greeter = 'Hi there, ' + a + ' ' + b.name;
        });
    
        myApp.provider('greetProvider', function(a) {
            this.firstName = a;
            this.$get = function(b) {
                this.lastName = b.name;
                this.fullName = this.firstName + ' ' + this.lastName;
                return this;
            };
        });
    
        function MyCtrl($scope, greetService, greetProvider) {
            $scope.servGreet = greetService.greeter;
            $scope.provGreet = greetProvider.fullName;
        }
    </script>
    
        
    55
    2015-04-21 18: 55: 29Z

    Это очень запутанная часть для новичка, и я попытался объяснить это простыми словами

    Служба AngularJS: используется для совместного использования служебных функций со ссылкой на службу в контроллере. Служба является одноэлементной по своей природе, поэтому для одного сервиса в браузере создается только один экземпляр, и одна и та же ссылка используется на всей странице.

    В сервисе мы создаем имена функций как свойство с этим объектом.

    AngularJS Factory: назначение Factory также совпадает с Service, однако в этом случае мы создаем новый объект и добавляем функции в качестве свойств этого объекта, а в конце возвращаем этот объект. р>

    AngularJS Provider: цель этого аналогична, однако Provider выдает выходные данные своей функции $get.

    Определение и использование Service, Factory и Provider объясняется по адресу http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider

        
    44
    2016-05-23 01: 44: 43Z
    1. Фабрика и предоставлениетакже являются одноэлементными объектами? Любой сканрио, где фабрики рекомендуются над услугами?
      2016-07-07 06: 28: 04Z

    Для меня лучший и самый простой способ понять разницу:

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

    Самый простой способ мышления следующий:

    • Сервис - это экземпляр одноэлементного объекта. Используйте сервисы, если хотите предоставить одноэлементный объект для своего кода.
    • Фабрика - это класс. Используйте фабрики, если вы хотите предоставить собственные классы для своего кода (это нельзя сделать с помощью сервисов, потому что они уже созданы).

    Пример фабричного «класса» представлен в комментариях, а также о разнице поставщиков.

        
    34
    2014-12-13 17: 03: 44Z
    1. как сервис может быть одноэлементным, если его экземпляр создается каждый раз, когда он используется? я могу обдумать это ...
      2015-10-05 22: 33: 41Z
    2. Служба создается только один раз во время разрешения зависимостей, а затем, когда вы запрашиваете службу у инжектора, вы всегда получаете один и тот же экземпляр. Это можно легко проверить здесь: jsfiddle.net/l0co/sovtu55t/1 , пожалуйста, запустите это с консолью. Консоль показывает, что служба создается только один раз.
      2015-10-06 08: 00: 34Z
    3. о, я вижу. я ожидал, что смогу буквально new MyService() или что-то в этом роде:)
      2015-10-06 18: 12: 02Z

    Мои разъяснения по этому вопросу:

    В основном все упомянутые типы (сервис, фабрика, поставщик и т. д.) просто создают и настраивают глобальные переменные (которые, конечно, являются глобальными для всего приложения), как это делали устаревшие глобальные переменные.

    Хотя глобальные переменные не рекомендуются, реальное использование этих глобальных переменных заключается в обеспечении внедрения зависимостей , передавая переменная для соответствующего контроллера.

    При создании значений для «глобальных переменных» существует много уровней сложности:

    1. Constant
      Это определяет фактическую константу, которая не должна изменяться в течение всего приложения, как и константы в других языках (чего нет в JavaScript).
    2. Значение
      Это изменяемое значение или объект, и он служит некоторой глобальной переменной, которую можно даже внедрить при создании других служб или фабрик (см. Далее). Однако это должно быть « литеральное значение », что означает, что нужно выписать фактическое значение и не может использовать какую-либо логику вычислений или программирования (другими словами 39 или myText или {prop: "value"} в порядке, а 2 +2 - нет).
    3. Завод
      Более общее значение, которое можно вычислить сразу. Он работает путем передачи функции в AngularJS с логикой, необходимой для вычисления значения, и AngularJS выполняет ее, и сохраняет возвращаемое значение в именованной переменной.
      Обратите внимание, что можно вернуть объект (в этом случае он будет функционировать аналогично службе ) или функцию (которая будет сохранена в переменной как функция обратного вызова).
    4. Сервис
      Служба - это более урезанная версия factory , которая действительна только в том случае, если значение является объектом, и она позволяет писать любую логику непосредственно в функции (как если бы это был конструктор), а также объявление и доступ к собственному объектусвязывается с использованием ключевого слова this .
    5. Provider
      В отличие от сервиса, который является упрощенной версией factory , провайдер представляет собой более сложный, но более гибкий способ инициализации «глобальных» переменных, при этом наибольшей гибкостью является возможность задания значений из приложения. .config.
      Он работает подобно использованию комбинации service и provider , передавая поставщику функцию, свойства которой объявлены с использованием ключевого слова this , которое может быть используется от app.config.
      Затем требуется отдельная функция $. get , которая выполняется AngularJS после установки указанных свойств через файл app.config, и эта функция $. get ведет себя как и factory выше, тем, что его возвращаемое значение используется для инициализации «глобальных» переменных.
    33
    2014-12-13 18: 25: 30Z

    Мое понимание очень просто ниже.

    Фабрика:   Вы просто создаете объект внутри фабрики и возвращаете его.

    Услуги:

    У вас просто есть стандартная функция, которая использует это ключевое слово для определения функции.

    Provider:

    Существует определенный объект $get, который можно использовать для получения объекта, возвращающего данные.

        
    26
    2014-12-13 17: 11: 52Z
    1. Разве вы не перепутали Фабрику и Сервис? Служба создает, где фабрика возвращает.
      2014-11-09 06: 06: 31Z
    2. Когда вы объявляете имя службы как вводимый аргумент, вам будет предоставлен экземпляр функции. Другими словами, новый FunctionYouPassedToService (). Этот экземпляр объекта становится сервисным объектом, который AngularJS регистрирует и затем внедряет в другие сервисы /контроллеры, если это необходимо. //factory Когда вы объявляете factoryname как вводимый аргумент, вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory.
      2014-11-23 04: 31: 16Z
    3. Хорошо, так что ... в угловом виде фабрика представляет собой singleton , где «сервис» - это фактически фабрика (в общем дизайне шаблоны терминов)
      2014-11-23 08: 24: 45Z

    Сводка из угловых документов :

    • Существует пять типов рецептов, которые определяют, как создавать объекты: Value а> , Factory , Сервис , поставщик и Константа .
    • Завод и Сервис являются наиболее часто используемыми рецептами. Единственное различие между ними заключается в том, что рецепт Сервис лучше работает для объектов пользовательского типа, тогда как Фабрика может создавать примитивы и функции JavaScript.
    • Рецепт Provider является основным типом рецепта, а все остальные являются просто синтаксическим сахаром.
    • Поставщик - самый сложный тип рецепта. Вам это не нужно, если вы не создаете многократно используемый код, который требует глобальной настройки.

     введите описание изображения здесь

    Лучшие ответы от SO:

    https://stackoverflow.com/a/26924234/165673 (< - ХОРОШО) https://stackoverflow.com/a/27263882/165673
    https://stackoverflow.com/a/16566144/165673

        
    24
    2017-05-23 12: 34: 54Z

    Все хорошие ответы уже. Я хотел бы добавить еще несколько пунктов в разделах Сервис и Фабрика . Вместе с разницей между сервисом /фабрикой. И также могут возникнуть вопросы, такие как:

    1. Должен ли я использовать сервис или фабрику? В чем разница?
    2. Они делают то же самое или ведут себя одинаково?

    Давайте начнем с разницы между обслуживанием и фабрикой:

    1. Оба являются синглетонами . Каждый раз, когда Angular находит их как зависимость, он создает один экземпляр службы /фабрики. Как только экземпляр создан, этот экземпляр используется навсегда.

    2. Может использоваться для моделирования объекта с поведением : оба могут иметь методы, внутренние переменные состояния и т. д. Хотя способ написания этого кода будет другим.

    Услуги:

    Служба - это функция конструктора, и Angular создаст ее экземпляр, вызвав новый yourServiceName(). Это означает пару вещей.

    1. Функции и переменные экземпляра будут свойствами this.
    2. Вам не нужно возвращать значение. Когда Angular вызывает 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 очень похоже, и некоторые люди скажут   что либо один в порядке. Это несколько верно, но мне легче   следуйте советам руководства по стилю Джона Папы и просто придерживайтесь   заводы. **

        
    17
    2017-10-10 07: 34: 44Z

    Дополнительное пояснение: фабрики могут создавать функции /примитивы, а сервисы - нет. Проверьте это jsFiddle на основе Epokk: 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-сервисы противы-заводы-в-угловой /

        
    16
    2015-01-31 10: 22: 22Z

    Уже есть хорошие ответы, но я просто хочу поделиться этим.

    Прежде всего: Provider - это способ /рецепт для создания service (одноэлементного объекта), который должен быть введен с помощью $инжектора (как AngulaJS использует шаблон IoC).

    И Value, Factory, Service и Constant (4 способа) - синтаксический сахар по сравнению с Provider way /recepie.

    Это Service vs Factory часть была покрыта: https://www.youtube.com/watch?v=BLzNCkPn3ao

    Сервис - это ключевое слово new, которое, как мы знаем, делает 4 вещи:

    1. создает новый объект
    2. связывает его со своим объектом prototype
    3. соединяет context с this
    4. и возвращает this

    А Factory - это все о Factory Pattern - содержит функции, которые возвращают объекты, подобные этой службе.

    1. возможность использовать другие сервисы (есть зависимости)
    2. инициализация службы
    3. отложенная /отложенная инициализация

    И это простое /короткое видео: также охватывает поставщика : https: //www.youtube.com/watch?v=HvTZbQ_hUZY (там видно, как они переходят с завода на провайдера)

    Рецепт

    Provider используется главным образом в конфигурации приложения до его полного запуска /инициализации.

        
    16
    2015-06-23 14: 04: 46Z

    После прочтения всех этих постов это создало больше путаницы для меня .. Но, тем не менее, все это является полезной информацией ... наконец, я нашел следующую таблицу, которая даст информацию с простым сравнением

    • Инжектор использует рецепты для создания объектов двух типов: сервисы и объекты специального назначения
    • Существует пять типов рецептов, которые определяют, как создавать объекты: значение, Фабрика, Сервис, Поставщик и Постоянный.
    • Фабрика и Сервис - наиболее часто используемые рецепты. Единственное различие между ними заключается в том, что рецепт Service работает лучше для объектов пользовательского типа, тогда как Factory может создавать примитивы и функции JavaScript.
    • Рецепт провайдера - это основной тип рецепта, а все остальные - просто синтаксический сахар.
    • Поставщик - самый сложный тип рецепта. Вам это не нужно, если вы не создаете многократно используемый код, который требует глобальной настройки.
    • Все объекты специального назначения, за исключением контроллера, определяются с помощью фабричных рецептов.

     введите описание изображения здесь

    И для начинающего, поймите: - Это может не исправить вариант использования, но на высоком уровне это то, что использует сценарий для этих трех.

    1. Если вы хотите использовать в модуле конфигурации угловой модуль должен быть создан как поставщик

    р>

     
    angular.module('myApp').config(function($testProvider){
    $testProvider.someFunction();
    })
    1. Ajax-вызов или сторонняя интеграция должны быть сервисом .
    2. Для манипуляций с данными создайте его как factory

    Для базовых сценариев фабрика и сервис ведут себя одинаково.

        
    14
    2017-07-27 06: 48: 50Z

    Вот пример кода, который я придумал как шаблон кода для фабрики объектов в 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
    

    ; р>     

    13
    2015-03-30 15: 57: 37Z

    Использование в качестве ссылки этой страницы и документации (которая, по-видимому, значительно улучшилась с момента последней раз, когда я посмотрел), я собрал следующую (-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);
        };
    });
    

    Рабочая демонстрационная версия .

        
    12
    2015-01-30 20: 04: 12Z

    Этот ответ касается темы /вопроса

    как Factory, Service и Constant - просто синтаксический сахар поверх рецепта поставщика?

    ИЛИ сильный> р>

    как фабрика, сервис и провайдеры являются внутренним симиларом

    в основном то, что происходит,

    Когда вы делаете 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 () для блока конфигурации

        
    12
    2015-11-06 02: 07: 53Z

    Я знаю много отличных ответов, но я должен поделиться своим опытом использования
    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;
    ... 
    
        
    11
    2015-04-07 01: 25: 52Z

    Немного опоздал на вечеринку. Но я подумал, что это более полезно для тех, кто хотел бы узнать (или иметь ясность) о разработке пользовательских служб 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>
        
    10
    2015-12-28 19: 26: 13Z

    Просто чтобы прояснить ситуацию, из источника AngularJS вы можете увидеть, что служба просто вызывает фабричную функцию, которая, в свою очередь, вызывает функцию провайдера:

     
    function factory(name, factoryFn) { 
        return provider(name, { $get: factoryFn }); 
    }
    
    function service(name, constructor) {
        return factory(name, ['$injector', function($injector) {
          return $injector.instantiate(constructor);
        }]);
    }
    
        
    10
    2016-01-21 20: 44: 58Z

    Давайте обсудим три способа работы с бизнес-логикой в ​​AngularJS простым способом: ( Вдохновленный курсом Яакова Coursera AngularJS )

    SERVICE

    Синтаксис:

    app.js

     
     var app = angular.module('ServiceExample',[]);
     var serviceExampleController =
                  app.controller('ServiceExampleController', ServiceExampleController);
     var serviceExample = app.service('NameOfTheService', NameOfTheService);
    
     ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
    
    function ServiceExampleController(NameOfTheService){
         serviceExampleController = this;
         serviceExampleController.data = NameOfTheService.getSomeData();
     }
    
    function NameOfTheService(){
         nameOfTheService = this;
         nameOfTheService.data = "Some Data";
         nameOfTheService.getSomeData = function(){
               return nameOfTheService.data;
         }     
    }
    

    index.html

     
    <div ng-controller = "ServiceExampleController as serviceExample">
       {{serviceExample.data}}
    </div>
    

    Особенности сервиса:

    1. Ленивый экземпляр . Если он не введен, он никогда не будет создан. Таким образом, чтобы использовать его, придется ввести его в модуль.
    2. Singleton : при внедрении в несколько модулей все будут иметь доступ только к одному конкретному экземпляру. Вот почему очень удобно обмениваться данными между разными контроллерами.

    ФАБРИКА

    Сначала давайте посмотрим на синтаксис:

    app.js

     
    var app = angular.module('FactoryExample',[]);
    var factoryController = app.controller('FactoryController', FactoryController);
    var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
    var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
    
    //first implementation where it returns a function
    function NameOfTheFactoryOne(){
       var factory = function(){
          return new SomeService();
        }
       return factory;
    }
    
    //second implementation where an object literal would be returned
    function NameOfTheFactoryTwo(){
       var factory = {
          getSomeService : function(){
              return new SomeService();
           }
        };
       return factory;
    }
    

    Теперь используем два выше в контроллере:

     
     var factoryOne = NameOfTheFactoryOne() //since it returns a function
     factoryOne.someMethod();
    
     var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
     factoryTwo.someMethod();
    

    Особенности фабрики:

    1. Следует шаблону фабричного дизайна. Фабрика - это центральное место, где производятся новые объекты или функции.
    2. Производит не только одиночные, но и настраиваемые сервисы.
    3. Метод .service() - это фабрика , которая всегда предоставляет один и тот же тип сервиса, который является одноэлементным, и без какого-либо простого способа настройки его поведения. Этот метод .service() обычно используется как ярлык для чего-то, что не требует какой-либо настройки.

    ПРОВАЙДЕР

    Давайте снова сначала посмотрим на синтаксис:

     
    angular.module('ProviderModule', [])
    .controller('ProviderModuleController', ProviderModuleController)
    .provider('ServiceProvider', ServiceProvider)
    .config(Config); //optional
    
    Config.$inject = ['ServiceProvider'];
    function Config(ServiceProvider) {
      ServiceProvider.defaults.maxItems = 10; //some default value
    }
    
    
    ProviderModuleController.$inject = ['ServiceProvider'];
    function ProviderModuleController(ServiceProvider) {
      //some methods
    }
    
    function ServiceProvider() {
      var provider = this;
    
      provider.defaults = {
        maxItems: 10
      };
    
      provider.$get = function () {
        var someList = new someListService(provider.defaults.maxItems);
    
        return someList;
      };
    }
    
    }
    

    Особенности провайдера:

    1. Провайдер - это самый гибкий метод создания сервисов в Angular.
    2. Мало того, что мы можем создать фабрику, которая динамически настраивается, но во время использования фабрики с помощью метода провайдера мы могли настраивать фабрику только один раз при начальной загрузке всего нашего приложения.
    3. Затем фабрика может использоваться во всем приложении с пользовательскими настройками. Другими словами, мы можем настроить эту фабрику до запуска приложения. Фактически в угловой документации упоминается, что метод провайдера - это то, что фактически выполняется за кулисами, когда мы конфигурируем наши сервисы с помощью методов .service или .factory.
    4. $get - это функция, которая напрямую связана с экземпляром провайдера. Эта функция является функцией фабрики . Другими словами, он похож на тот, который мы используем для предоставления методу .factory. В этой функции мы создаем наш собственный сервис. Это свойство $get, то есть функция, которая делает провайдера провайдером . AngularJS ожидает, что у провайдера будет свойство $get, значением которого является функция, которую Angular будет рассматривать как фабричную функцию. Но что делает всю эту настройку провайдера особенной, так это то, что мы можем предоставить около config объект внутри поставщика услуг, и это обычно идет со значениями по умолчанию, которые мы можем позже перезаписать на шаге, где мы можем настроить все приложение.
    9
    2016-12-09 09: 31: 42Z

    Фабрика .Теперь вы на самом деле создаете объект внутри фабрики и возвращаете его.
    service: Служба: у вас есть стандартная функция, использующая ключевое слово this для определения функции.
    provider : у провайдера есть $get, который вы определяете, и его можно использовать для получения объекта, который возвращает данные.

        
    7
    2015-03-04 11: 12: 38Z

    По сути, Поставщик, Завод и Сервис - это Сервисы. Фабрика - это особый случай службы, когда все, что вам нужно, это функция $get (), позволяющая писать ее с меньшим количеством кода.

    Основные различия между Сервисами, Фабриками и Поставщиками заключаются в их сложности. Сервисы - это самая простая форма, фабрики немного более устойчивы, а провайдеры настраиваются во время выполнения.

    Вот краткое изложение того, когда использовать каждый из них:

    Завод . Предоставляемое вами значение необходимо рассчитывать на основе других данных.

    Сервис . Вы возвращаете объект с методами.

    Поставщик . На этапе настройки вы хотите настроить объект, который будет создан до его создания. Используйте поставщика в основном в конфигурации приложения до полной инициализации приложения.

        
    7
    2016-12-28 11: 41: 07Z
    1. ошибка. Value, Factory, Service и Constant - это просто синтаксический сахар на вершине рецепта поставщика. Документы Angularjs - поставщики
      2017-02-08 07: 25: 48Z
    2. да, я согласен, теперь с угловым 4 у нас больше нет этой головной боли
      2018-02-13 21: 18: 46Z

    1.Услуги - это одноэлементные объекты, которые создаются при необходимости и никогда не очищаются до конца жизненного цикла приложения (когда браузер закрыт). Контроллеры уничтожаются и очищаются, когда они больше не нужны.

    2. Самый простой способ создать сервис - использовать метод factory (). Метод factory () позволяет нам определять службу, возвращая объект, который содержит функции службы и данные службы. Функция определения сервиса - это место, где мы размещаем наши инъекционные сервисы, такие как $http и $q. Пример:

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

    Использование factory () в нашем приложении

    В нашем приложении легко использовать фабрику, поскольку мы можем просто вставить ее туда, где она нам нужна во время выполнения.

     
    angular.module('myApp')
    .controller('MainController', function($scope, User) {
      $scope.saveUser = User.save;
    });
    
    1. Метод service (), с другой стороны, позволяет нам создавать сервис, определяя функцию конструктора. Мы можем использовать прототипный объект для определения нашего сервиса вместо необработанного объекта JavaScript. Подобно методу factory (), мы также установим инъецируемые элементы в определении функции.
    2. Самый низкий способ создания службы - использование метода provide (). Это единственный способ создать службу, которую мы можем настроить с помощью функции .config (). В отличие от предыдущих методов, мы устанавливаем инъецируемые в определении функции this. $Get ().
    4
    2016-10-30 23: 39: 31Z

    Синтаксический сахар - это разница . Нужен только провайдер. Или, другими словами, реальным углом является только провайдер, все остальные являются производными (для уменьшения кода). Существует также простая версия, называемая Value (), которая возвращает только значение, без вычисления или функции. Четное значение получено от поставщика!

    Итак, почему такие сложности, почему мы не можем просто использовать провайдера и забыть обо всем остальном? Предполагается, что это поможет нам легче писать код и лучше общаться. И ответ будет сложнее, чем сложнее он будет, тем лучше будет продажа фреймворка.

    • поставщик tМожет возвращать значение = Значение
    • Поставщик, который может просто создать экземпляр и вернуть = Factory (+ Value)
    • Поставщик, который может создать экземпляр + сделать что-то = Служба (+ Фабрика, + Значение)
    • Провайдер = должен содержать свойство с именем $get (+ Factory, + Service, + Value)

    Угловая инъекция дает нам первый намек в достижении этого заключения.

    "$injector используется для извлечения экземпляров объектов, как определено provider ", не службой, не фабрикой, а поставщиком.

    И лучшим ответом будет: «Сервис Angular создается фабрикой сервисов. Эти фабрики сервисов являются функциями, которые, в свою очередь, создаются сервис-провайдером. Провайдеры сервисов являются функциями-конструкторами. При создании экземпляра они должны содержать свойство с именем $get, которое содержит сервис заводская функция. "

    Так что мастер провайдер и инжектор и все встанет на свои места :). И в Typescript становится интересным, когда $get может быть реализован в провайдере путем наследования от IServiceProvider.

        
    - 3
    2016-04-05 13: 13: 00Z
источник размещен Вот