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

3178

В чем разница между Service, Provider и Factory в AngularJS?

  • 237
    Я обнаружил, что все угловые термины были пугающими для начинающих. Мы начали с этой таблицы, которую нашим программистам было немного легче понять, изучая Angular demisx.github.io/angularjs/2014/09/14/… . Надеюсь, это тоже поможет вашей команде.
  • 6
    На мой взгляд, лучший способ понять разницу - это использовать собственную документацию Angular: docs.angularjs.org/guide/providers это очень хорошо объяснено и использует специфический пример, чтобы помочь вам понять это.
Показать ещё 4 комментария
Теги:
dependency-injection
angularjs-service
angularjs-factory
angularjs-provider

31 ответ

2951
Лучший ответ

Из списка рассылки AngularJS я получил удивительный поток, в котором объясняется, что служба vs factory vs provider и их использование инъекций. Компиляция ответов:

Услуги

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

Заводы

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

Провайдеры

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

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

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

Вот еще одно объяснение Миско:

provide.value('a', 123);

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

В этом случае инжектор просто возвращает значение as is. Но что, если вы хотите вычислить значение? Затем используйте factory

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

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

So factory - это функция, которая отвечает за создание значения. Обратите внимание, что функция factory может запрашивать другие зависимости.

Но что, если вы хотите быть более OO и иметь класс Greeter?

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

Затем для создания экземпляра вам нужно написать

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

Тогда мы могли бы запросить "greeter" в контроллере, подобном этому

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

Но это слишком многословно. Более короткий способ написать это будет provider.service('greeter', Greeter);

Но что, если мы хотим настроить класс Greeter перед инъекцией? Тогда мы могли бы написать

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

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

  this.$get = function(a) {
    return new Greeter(a);
  };
});

Тогда мы можем это сделать:

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

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

В качестве побочного примечания, service, factory и value все получены от поставщика.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};
  • 57
    См. Также stackoverflow.com/a/13763886/215945, в котором рассматриваются различия между обслуживанием и фабрикой.
  • 3
    В редакторе 611 я добавил использование угловых констант и значений. Чтобы продемонстрировать отличия от других уже показано. jsbin.com/ohamub/611/edit
Показать ещё 9 комментариев
797

JS Fiddle Demo

Пример "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>
  • 2
    Разве this не меняет контекст в функции $get ? - вы больше не обращаетесь к конкретному провайдеру в этой функции.
  • 12
    @Nate: фактически this не меняет контекст, потому что вызывается new Provider() . $ Get (), где Provider - это функция, передаваемая в app.provider . То есть, что $get() вызывается как метод для созданного Provider , так что this будет ссылаться на Provider как Provider в примере.
Показать ещё 5 комментариев
621

TL; DR

1). Когда вы используете Factory, вы создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Когда вы передадите этот factory в свой контроллер, эти свойства объекта теперь будут доступны в этом контроллере через ваш 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 запускает его за кулисами с помощью нового ключевого слова. Из-за этого вы добавите свойства, чтобы "это, и служба вернет" это. Когда вы передаете услугу в свой контроллер, эти свойства "теперь будут доступны на этом контроллере через вашу службу".

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



Non TL; DR

1) Factory
Фабрики - самый популярный способ создания и настройки сервиса. Theres действительно не намного больше, чем TL, сказал DR. Вы просто создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Затем, когда вы передаете factory в свой контроллер, эти свойства объекта теперь будут доступны в этом контроллере через ваш factory. Ниже приведен более подробный пример.

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

Теперь любые свойства, которые мы прикрепляем к сервису, будут доступны нам, когда мы передадим myFactory в наш контроллер.

Теперь добавим некоторые частные переменные в нашу функцию обратного вызова. Они не будут напрямую доступны из контроллера, но мы в конечном итоге настроим некоторые методы getter/setter на "службе", чтобы иметь возможность изменять эти "частные переменные", когда это необходимо.

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 - это функция, которая создаст и вернет наш дружественный iTunes URL.

Теперь, когда наши вспомогательные/частные переменные и функции находятся на месте, добавьте некоторые свойства в объект службы. Независимо от того, что мы ставим на "обслуживание", можно напрямую использовать внутри того, какой контроллер мы передаем "myFactory" .

Мы собираемся создавать методы setArtist и getArtist, которые просто возвращают или устанавливают исполнителя. Мы также создадим метод, который вызовет iTunes API с нашим созданным URL. Этот метод вернет обещание, которое будет выполнено после того, как данные вернутся из iTunes API. Если у вас не было большого опыта использования promises в 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;
});

Теперь наш factory завершен. Теперь мы можем ввести "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. Единственный сложный код, приведенный выше, заключается в том, что раньше вы не рассматривали promises. Поскольку callItunes возвращает обещание, мы можем использовать метод .then() и устанавливать значение $scope.data.artistData только после того, как наше обещание будет выполнено с данными iTunes. Вы заметите, что наш контроллер очень "тонкий" (это хорошая практика кодирования). Все наши логические и постоянные данные находятся в нашем сервисе, а не в нашем контроллере.

2) Сервис
Возможно, самое большое, что нужно знать при создании службы, - это то, что она создавалась с помощью нового ключевого слова. Для вас JavaScript-гуру это должно дать вам большой намек на природу кода. Для тех из вас, у кого ограниченный фон в JavaScript или для тех, кто не знаком с тем, что на самом деле делает "новое ключевое слово", рассмотрим некоторые основы JavaScript, которые в конечном итоге помогут нам понять природу Сервиса.

Чтобы действительно увидеть изменения, возникающие при вызове функции с помощью нового ключевого слова, создайте функцию и вызовите ее с помощью нового ключевого слова, а затем покажите, что делает интерпретатор, когда видит новое ключевое слово. Конечные результаты будут одинаковыми.

Сначала создадим наш конструктор.

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

Это типичная функция конструктора JavaScript. Теперь всякий раз, когда мы вызываем функцию 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". Первое, что вы должны заметить, это то, что после использования "нового в нашем примере" удалось вызвать метод (sayName) на "tyler", как если бы это был объект, потому что это так. Итак, сначала мы знаем, что наш конструктор Person возвращает объект, можем ли мы видеть это в коде или нет. Во-вторых, мы знаем, что поскольку наша функция sayName находится на прототипе, а не непосредственно на экземпляре Person, объект, возвращаемый функцией Person, должен делегировать его прототипу при неудачном поиске. В более простых терминах, когда мы вызываем tyler.sayName(), интерпретатор говорит: "ОК, я собираюсь посмотреть на" только что созданный объект tyler ", найти функцию sayName, а затем вызвать его. Подождите, я не вижу его здесь - все, что я вижу, это имя и возраст, позвольте мне проверить прототип. Да, похоже, что это на прототипе, позвольте мне называть его.".

Ниже приведен код того, как вы можете думать о том, что "новое ключевое слово действительно делает в JavaScript". В основном это пример кода вышеприведенного параграфа. Ive положил "представление интерпретатора или способ, которым интерпретатор видит код внутри заметок".

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 должно быть понятнее.

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

В отличие от того, что мы изначально сделали с примером factory, нам не нужно создавать объект, а затем возвращать этот объект, потому что, как уже упоминалось много раз ранее, мы использовали ключевое слово 'new, чтобы интерпретатор создавал этот объект, делегировать его прототипу, а затем вернуть его нам без необходимости выполнять работу.

Прежде всего, давайте создадим нашу "частную" и вспомогательную функцию. Это должно выглядеть очень хорошо, поскольку мы сделали то же самое с нашим factory. Я не буду объяснять, что делает каждая строка, потому что я сделал это в примере factory, если вы запутались, перечитайте пример factory.

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

});

Теперь, как и в нашем factory, setArtist, getArtist и callItunes будут доступны в том, какой контроллер мы передаем myService. Heres контроллер myService (который почти точно совпадает с нашим контроллером factory).

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 вашего приложения. Это имеет огромное значение, если вам нужно изменить часть своего объекта службы до того, как он будет доступен везде в вашем приложении. Хотя они очень похожи на Службы/Фабрики, есть несколько различий, которые хорошо обсуждают.

Сначала мы создали наш Поставщик аналогичным образом с нашей службой и factory. Переменные ниже являются нашей "частной и вспомогательной".

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 и поэтому доступны для изменения до того, как они будут доступны в другом месте (также показано выше). Важно отметить, что эти переменные необходимо привязать к" этому ключевому слову. В нашем примере доступно только "thingFromConfig" для изменения в app.config. Третий раздел (показано ниже) - это все переменные/функции, которые будут доступны в вашем контроллере, когда вы передадите "myProvider" в этот конкретный контроллер.

При создании службы с провайдером единственными свойствами/методами, которые будут доступны в вашем контроллере, являются те свойства/методы, которые возвращаются из функции $get(). Код ниже ставит $get on '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
    }
  }
});

Теперь, как и в наших factory и сервисах, setArtist, getArtist и callItunes будут доступны в любом контроллере, в который мы передаем myProvider. Heres контроллер myProvider (почти такой же, как наш factory/Service controller).

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

Как уже упоминалось ранее, вся цель создания службы с провайдером заключается в том, чтобы иметь возможность изменять некоторые переменные с помощью функции 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, это будет "Это предложение было установлено....

  • 10
    Единственная часть, которая отсутствует в этой превосходной статье, - это относительные преимущества использования сервиса над фабрикой; что ясно объясняется в принятом ответе Лиор
  • 2
    FWIW (может быть, не очень), вот блоггер, который имеет проблемы с Angular, и не любит providerProvider codeofrob.com/entries/you-have-ruined-javascript.html
Показать ещё 6 комментариев
481

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

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

Самый многословный, но также самый полный из них - Провайдер рецепт. остальные четыре типа рецепта - значение, Factory, служба и Константа - - это просто синтаксический сахар поверх рецепта поставщика.

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

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

  • Постоянный рецепт похож на рецепт Value, за исключением того, что он позволяет вам определять службы, доступные в фазе config. Рано, чем услуги, созданные с использованием рецепта Value. В отличие от значений, они не могут быть украшены с помощью decorator.
См. документацию поставщика.
  • 2
    Значит сервис и завод по сути одинаковы? Использование одного другого обеспечивает ничего, кроме альтернативного синтаксиса?
  • 2
    @ Матт, да, сервис - это лаконичный способ, когда у вас уже есть собственная функция, которую вы хотите представить как сервис. Из документов: myApp.factory ('unicornLauncher', ["apiToken", function (apiToken) {вернуть новый UnicornLauncher (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
Показать ещё 2 комментария
210

Понимание AngularJS Factory, службы и провайдера

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

В Docs Сервис /Factory:

  • Леновый экземпляр - Angular создает экземпляр сервиса /factory, когда компонент приложения зависит от него.
  • Синглоты - каждый компонент в зависимости от службы получает ссылку на один экземпляр созданный службой factory.

Factory

A factory - это функция, в которой вы можете манипулировать/добавлять логику перед созданием объекта, затем возвращается вновь созданный объект.

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

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

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

Сервис

Просто взглянув на службы, подумайте о прототипе массива. Служба - это функция, которая создает новый объект с использованием ключевого слова "новое". Вы можете добавить свойства и функции к объекту службы с помощью ключевого слова this. В отличие от Factory, он ничего не возвращает (он возвращает объект, который содержит методы/свойства).

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

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

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

Provider

Поставщик используется для создания настраиваемого объекта службы. Вы можете настроить параметры службы из функции конфигурации. Он возвращает значение с помощью функции $get(). Функция $get запускается на этапе выполнения в angular.

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 доступен только провайдер, тогда как службы и factory нет.

Надеемся, что это прояснило ваше понимание о Factory, сервисе и поставщике.

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

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

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

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

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

  • a сохраненное значение происходит от запуска fn.
  • b s сохраненное значение происходит от new ing fn.
  • c s хранимое значение происходит от первого получения экземпляра new ing fn, а затем запускает метод $get экземпляра.

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

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

Вот почему мы используем this в сервисах и определяем this.$get у поставщиков.

  • 2
    Мне также нравится этот ответ больше всего. Смысл всех их заключается в предоставлении доступа к объекту при необходимости через DI. Обычно у вас все хорошо с factory . Единственной причиной существования service являются языки, такие как CoffeeScript, TypeScript, ES6 и т. Д., Поэтому вы можете использовать их синтаксис класса. provider требуются только в том случае, если ваш модуль используется в нескольких приложениях с разными настройками с помощью app.config() . Если ваш сервис является чисто одноэлементным или способен создавать экземпляры чего-либо, зависит только от вашей реализации.
133

Служба против поставщика vs factory:

Я стараюсь, чтобы это было просто. Все о базовой концепции JavaScript.

Прежде всего, расскажите о сервисах в AngularJS!

Что такое Сервис: В AngularJS Сервис - не что иное, как однострочный JavaScript-объект, который может хранить некоторые полезные методы или свойства. Этот одноэлементный объект создается на основе ngApp (Angular app), и он распределяется между всеми контроллерами в текущем приложении. Когда Angularjs создает экземпляр объекта службы, он регистрирует этот служебный объект с уникальным именем службы. Поэтому каждый раз, когда нам нужен экземпляр службы, Angular искать реестр для этого имени службы и возвращает ссылку на объект службы. Таким образом, мы можем вызывать метод, свойства доступа и т.д. В объекте службы. У вас может возникнуть вопрос, можете ли вы также поместить свойства, методы в объект объекта scope контроллеров! Итак, зачем вам нужен служебный объект? Ответы: услуги распределяются между несколькими областями контроллера. Если вы поместите некоторые свойства/методы в объект области контроллера, он будет доступен только для текущей области. Но когда вы определяете методы, свойства объекта службы, он будет доступен по всему миру и может быть доступен в любой области контроллера, введя эту службу.

Итак, если есть три области контроллера, пусть это будет контроллерА, контроллер Б и контроллерС, все будут иметь один и тот же экземпляр службы.

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

Как создать службу?

AngularJS предоставляет различные способы регистрации услуги. Здесь мы сосредоточимся на трех методах factory (..), service (..), provider (..);

Используйте эту ссылку для ссылки на код

Factory:

Мы можем определить функцию factory, как показано ниже.

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 использует "новое" ключевое слово и вызывает функцию-конструктор, как показано ниже.

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 предоставит его функции factory/constructor, которые создают наш экземпляр служб. В таком случае функция 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 используйте функцию factory, которая возвращает экземпляр службы. serviceInstance = fnFactory();

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

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

79

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

Изображение 3630

Здесь статья изображена от:

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

62

Factory

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

Пример:

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, который будет кэшироваться и вводиться, когда запрашивается услуга. Поскольку для создания экземпляра службы использовался новый, ключевое слово 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, которая будет кэшироваться и вводиться при запросе службы.

Поставщики позволяют настроить поставщика до. Угловой_JS вызывает метод $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');
});
52

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

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

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

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

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

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

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

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

Поставщик AngularJS: цель этого снова такая же, однако провайдер дает результат своей функции $get.

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

  • 1
    Фабрика и провайдеры тоже одноэлементные объекты? Любой сканрио, где фабрики рекомендуются поверх услуг?
33

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

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

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

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

  • Constant
    Это определяет фактическую константу, которая не должна быть изменена во время всего приложения, так же как константы на других языках (что-то, чего не хватает JavaScript).
  • Значение
    Это модифицируемое значение или объект, и оно служит некоторой глобальной переменной, которую можно даже вводить при создании других сервисов или фабрик (см. Далее). Однако это должно быть "буквальное значение", что означает, что нужно записать фактическое значение и не может использовать какую-либо логику вычисления или программирования (другими словами, 39 или myText или {prop: "value" } в порядке, но 2 +2 нет).
  • Factory
    Более общее значение, которое можно вычислить сразу. Он работает, передавая функцию AngularJS с логикой, необходимой для вычисления значения, и функция AngularJS выполняет ее, и она сохраняет возвращаемое значение в названной переменной.
    Обратите внимание, что можно вернуть объект (в этом случае он будет функционировать аналогично службе) или функцию (которая будет сохранена в переменной как функция обратного вызова).
  • Сервис
    Служба является более урезанной версией factory, которая действительна только тогда, когда значение является объектом, и позволяет записывать любую логику непосредственно в функции (как если бы это был конструктор), а также объявлять и доступ к свойствам объекта с помощью этого ключевого слова.
  • Provider
    В отличие от службы, которая является упрощенной версией factory, поставщик является более сложным, но более гибким способом инициализации "глобальных" переменных, причем наибольшей гибкостью является возможность устанавливать значения из app.config.
    Он работает как комбинация сервиса и поставщика, передавая провайдеру функцию, которая имеет свойства, объявленные с использованием этого ключевого слова, которые могут использоваться из app.config.
    Затем он должен иметь отдельную функцию $.get, которая выполняется AngularJS после установки вышеуказанных свойств с помощью файла app.config, и эта функция $.get ведет себя так же, как и factory выше, в том, что ее Возвращаемое значение используется для инициализации "глобальных" переменных.
32

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

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

Как AngularJS создает экземпляры определенных компонентов (упрощенных):

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

// factory
var angularFactory = factory(injection);

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

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

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

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

Пример factory "class" приведен в комментариях, а также разница между поставщиками.

  • 0
    как сервис может быть одноэлементным, если он создается каждый раз, когда его используют? я могу обдумать это ...
  • 0
    Служба создается только один раз во время разрешения зависимости, а затем, когда вы запрашиваете службу у инжектора, вы получаете всегда один и тот же экземпляр. Это можно легко проверить здесь: jsfiddle.net/l0co/sovtu55t/1 , пожалуйста, запустите его с консоли. Консоль показывает, что служба создается только один раз.
Показать ещё 1 комментарий
25

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

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

Услуги:

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

Provider:

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

  • 0
    Разве вы не перепутали Фабрику и Сервис? Служба создает, где фабрика возвращается.
  • 0
    Когда вы объявляете имя службы в качестве вводимого аргумента, вам будет предоставлен экземпляр функции. Другими словами, новая функцияYouPassedToService (). Этот экземпляр объекта становится сервисным объектом, который AngularJS регистрирует и затем внедряет в другие сервисы / контроллеры, если это необходимо. // factory Когда вы объявляете factoryname как вводимый аргумент, вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory.
Показать ещё 1 комментарий
23

Сводка из Angular docs:

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

Изображение 3631


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

https://stackoverflow.com/questions/13762228/confused-about-service-vs-factory (< - GOOD) https://stackoverflow.com/questions/18939709/angularjs-when-to-use-service-instead-of-factory
https://stackoverflow.com/questions/16565105/when-creating-service-method-whats-the-difference-between-module-service-and-mo

15

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

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

И Значение Factory, сервис и константа (4 способа) - синтаксический сахар через поставщик путь/прием.

Существует часть Service vs Factory: https://www.youtube.com/watch?v=BLzNCkPn3ao

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

  • создает новый объект
  • связывает его с объектом prototype
  • соединяет context с this
  • и возвращает this

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

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

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

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

15

Дополнительное разъяснение состоит в том, что фабрики могут создавать функции/примитивы, в то время как службы не могут. Посмотрите jsFiddle на основе Epokk's: http://jsfiddle.net/skeller88/PxdSP/1351/.

factory возвращает функцию, которая может быть вызвана:

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

factory также может возвращать объект с помощью метода, который можно вызвать:

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

Служба возвращает объект с помощью метода, который можно вызвать:

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

Для получения дополнительной информации см. сообщение, которое я написал о различии: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/

14

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

  • Должен ли я использовать службу или factory? В чем разница?
  • Являются ли они одинаковыми или имеют одинаковое поведение?

Давайте начнем с разницы между Сервисом и factory:

  • Оба являются Singletons: всякий раз, когда Angular находит их как зависимость в первый раз, он создает один экземпляр службы /factory. После создания экземпляра тот же экземпляр используется навсегда.

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

Услуги:

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

  • Функции и переменные экземпляра будут свойствами this.
  • Вам не нужно возвращать значение. Когда Angular вызывает new yourServiceName(), он получит объект this со всеми свойствами, которые вы на нем наложили.

Пример примера:

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

Когда Angular внедряет эту службу MyService в контроллер, который зависит от этого, тот контроллер получит MyService, который он может вызвать функции, например, MyService.aServiceMethod().

Будьте осторожны с this:

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

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 снизу, заменить factory на Service, а itll работать:

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

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

Поэтому, когда Angular создает вашу службу с помощью нового MyService(), он получит этот объект api вместо экземпляра MyService.

Это поведение для любых сложных значений (объектов, функций), но не для примитивных типов.

Фабрики:

A factory - простая старая функция, которая возвращает значение. Возвращаемое значение - это то, что вводится в вещи, которые зависят от factory. Типичным шаблоном factory в Angular является возврат объекта с функциями в качестве свойств, например:

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

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

  return api;
});

Введенное значение для зависимости factory - это возврат factory s значение, и он не должен быть объектом. Это может быть функция

Ответы на выше 1 и 2 вопроса:

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

Я все еще называю их "сервисами", когда я говорю о инъекциях они как зависимости, однако.

Сервис/Factory поведение очень похоже, и некоторые люди скажут что один из них в порядке. Это несколько верно, но мне легче следуйте рекомендациям руководства по стилю Джона Папаса и просто придерживайтесь заводы. **

13

Вот некоторый код бройлеров, который я придумал как шаблон кода для объекта factory в AngularjS. Я использовал Car/CarFactory в качестве примера для иллюстрации. Делает простой код реализации в контроллере.

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

Вот более простой пример. Я использую несколько сторонних библиотек, которые ожидают объект "Позиция", отображающий широту и долготу, но с помощью разных свойств объекта. Я не хотел взломать код поставщика, поэтому я скорректировал объекты "Position", которые я проходил.

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

;

12

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

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

Изображение 3632

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

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

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

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

12

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

как Factory, служба и константа - это просто синтаксический сахар поверх рецепта поставщика?

ИЛИ

, как factory, servic и провайдеры являются simailar внутри

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

Когда вы создаете factory(), он устанавливает function во втором аргументе поставщику $get и возвращает его (provider(name, {$get:factoryFn })), все, что вы получаете, это provider, но нет свойства/метод, отличный от $get этого provider (означает, что вы не можете его настроить)

Исходный код factory

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 для вашей функции, которую вы предоставили, но вы можете предоставить что-либо дополнительно, чем $get, поскольку вы можете первоначально предоставить в provider() для блока конфигурации

12

Используя ссылку на эту страницу и документацию (которая, кажется, значительно улучшилась с момента последнего просмотра), я собрал следующее real (-ish) world demo, которая использует 4 из 5 вкусов провайдера; Value, Constant, Factory и полнофункциональный поставщик.

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

Работаем демо.

11

Я знаю много отличного ответа, но я должен поделиться своим опытом использования 1. service для большинства случаев дефолта
2. factory используется для создания службы, которая имеет конкретный экземпляр

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

и используя:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 
10

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

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

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

Немного поздно на вечеринку. Но я подумал, что это более полезно для тех, кто хотел бы узнать (или иметь ясность) о разработке Angular JS Custom Services с использованием factory, методологий обслуживания и провайдера.

Я наткнулся на это видео, в котором четко разъясняются методики factory, службы и провайдера для разработки пользовательских сервисов AngularJS:

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

Исходный код: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

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

Код для настраиваемой службы на основе < factory "выглядит следующим образом (который идет как с версиями sync, так и с асинхронными вызовами вместе с вызовом службы 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;
  }
]);

Код для "сервисной" методологии для пользовательских сервисов (это очень похоже на "factory", но отличается от синтаксической точки зрения):

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

Давайте обсудим три способа обработки бизнес-логики в AngularJS простым способом: (Вдохновленный курсом Yaakov 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>

Особенности обслуживания:

  • Lazily Instantiated: если он не вводится, он не будет создан. Поэтому для его использования нужно будет ввести его в модуль.
  • Singleton: если вы вводите несколько модулей, все будут иметь доступ только к одному конкретному экземпляру. Вот почему очень удобно обмениваться данными между разными контроллерами.

FACTORY

Сначала рассмотрим синтаксис:

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

Особенности Factory:

  • Выполняет шаблон дизайна factory. factory - это центральное место, которое создает новые объекты или функции.
  • Не только производит singleton, но и настраиваемые сервисы.
  • Метод .service() - это FACTORY, который всегда создает тот же тип сервиса, который является одноэлементным, и без какого-либо простого способа настроить его поведение. Этот метод .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;
  };
}

}

Возможности провайдера:

  • Поставщик - самый гибкий способ создания служб в Angular.
  • Мы не только можем создать factory, который будет динамически настраиваться, но во время использования factory с помощью метода провайдера мы можем настроить factory только один раз при загрузке всего нашего приложения.
  • factory может использоваться во всем приложении с пользовательскими настройками. Другими словами, мы можем настроить этот factory до запуска приложения. Фактически в документации angular упоминается, что метод поставщика - это то, что фактически выполняется за кулисами, когда мы настраиваем наши службы с помощью методов .service или .factory.
  • $get - это функция, которая напрямую привязана к экземпляру поставщика. Эта функция является функцией FACTORY. Другими словами, это точно так же, как тот, который мы используем для предоставления методу .factory. В этой функции мы создаем нашу собственную услугу. Это свойство $get, что функция является тем, что делает провайдер провайдером. AngularJS ожидает, что провайдер получит свойство $get, значение которого является функцией, которую angular будет рассматривать как функцию factory. Но то, что делает настройку всего этого провайдера очень особенным, заключается в том, что мы можем предоставить некоторый объект config внутри поставщика услуг, и обычно это происходит со значениями по умолчанию, которые мы можем позже перезаписать на этом этапе, где мы можем настроить все приложение.
7

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

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

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

Factory. Значение, которое вы предоставляете, должно рассчитываться на основе других данных.

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

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

  • 0
    эм. Value, Factory, Service и Constant - это всего лишь синтаксический сахар на вершине рецепта поставщика. Angularjs документы - провайдеры
  • 0
    да, я согласен, теперь с угловым 4 у нас больше нет этой головной боли
7

Factory: factory вы фактически создаете объект внутри factory и возвращаете его.
:. У вас есть стандартная функция, которая использует это ключевое слово для определения функции.
провайдер: Поставщик theres $определяет, что вы определяете, и его можно использовать для получения объекта, который возвращает данные.

4

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

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

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

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

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

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Метод service(), с другой стороны, позволяет нам создавать службу, определяя функцию-конструктор. Мы можем использовать прототипный объект для определения нашего сервиса вместо необработанного объекта javascript. Подобно методу factory(), также установите инъекции в определение функции.
  2. Самый низкий способ создания службы - использовать метод offer(). Это единственный способ создать сервис, который мы можем настроить с помощью функции .config(). В отличие от предыдущих методов, хорошо задайте инъекции в определенном определении. $Get() function.
0

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

Угловой предоставляет нам три способа создания и регистрации нашего собственного сервиса.

1) Фабрика

2) Обслуживание

3) Провайдер

Factory: фабрика - это простая функция, которая позволяет вам добавить некоторую логику перед созданием объекта. Он возвращает созданный объект.

Это просто набор функций, таких как класс. Следовательно, он может быть создан в разных контроллерах, когда вы используете его с помощью функции-конструктора.

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

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

Поставщик. Поставщик используется для создания настраиваемого объекта службы. Он возвращает значение с помощью функции $ get().

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

Выполните следующий код и посмотрите результат.

<!DOCTYPE html>
<html ng-app="app">
<head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    <meta charset=utf-8 />
    <title>JS Bin</title>
</head>
<body ng-controller="MyCtrl">
    {{serviceOutput}}
    <br/><br/>
    {{factoryOutput}}
    <br/><br/>
    {{providerOutput}}
    <script>
        var app = angular.module( 'app', [] );
        var MyFunc = function() {
            this.name = "default name";
            this.$get = function() {
                this.name = "new name"
                return "Hello from MyFunc.$get(). this.name = " + this.name;
            };
            return "Hello from MyFunc(). this.name = " + this.name;
        };
        // returns the actual function
        app.service( 'myService', MyFunc );
        // returns the function return value
        app.factory( 'myFactory', MyFunc );
        // returns the output of the function $get function
        app.provider( 'myProv', MyFunc );
        function MyCtrl( $scope, myService, myFactory, myProv ) {
            $scope.serviceOutput = "myService = " + myService;
            $scope.factoryOutput = "myFactory = " + myFactory;
            $scope.providerOutput = "myProvider = " + myProv;
        }
    </script>
</body>
</html>
-3

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

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


  • Поставщик, который может вернуть value = значение
  • Поставщик, который может просто экземпляр и return = Factory (+ значение)
  • Поставщик, который может instantiate + do something = Service (+ Factory, + Value)
  • Поставщик = должно содержать свойство, называемое $get (+ Factory, + Service, + Value)

Angular инъекция дает нам первый намек на достижение этого вывода.

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню