Вопрос: AngularJS: Сервис против поставщика и завода


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


3148


источник


Ответы:


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

Сервисы

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

Заводы

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

Провайдеры

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

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

Видеть Вот для предоставленного кода.

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

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

Но что, если вы хотите быть более 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;
  });
};

2792



Демо-версия 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>


793



TL; DR

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

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) Фабрика
Фабрики - самый популярный способ создания и настройки сервиса. Там действительно не намного больше, чем TL, сказал DR. Вы просто создаете объект, добавляете к нему свойства, а затем возвращаете тот же объект. Затем, когда вы передадите фабрику в свой контроллер, эти свойства объекта будут доступны в этом контроллере через ваш завод. Ниже приведен более обширный пример.

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.

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

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

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

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

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

Теперь, как на нашем заводе и в сервисе, 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;
});

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


617



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

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

Самый многословный, но и самый полный из них - Провайдер   рецепт. оставшиеся четыре Типы рецептов - стоимость, заводская, сервисная и   Константа - просто синтаксический сахар поверх рецепта поставщика ,

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

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


506



Понимание оборудования, услуг и поставщиков оборудования AngularJS

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

Из документов Услуги / 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;
});

Применение

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

обслуживание

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

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

Применение

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

поставщик

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

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

Применение

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

ЗАМЕТКА

Только провайдер будет доступен в фазе конфигурации угловой, тогда как   сервис и завод - нет.

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


221



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

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

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в провайдерах.


189



Service vs provider vs factory:

I am trying to keep it simple. It's all about basic JavaScript concept.

First of all, let's talk about services in AngularJS!

What is Service: In AngularJS, Service is nothing but a singleton JavaScript object which can store some useful methods or properties. This singleton object is created per ngApp(Angular app) basis and it is shared among all the controllers within current app. When Angularjs instantiate a service object, it register this service object with a unique service name. So each time when we need service instance, Angular search the registry for this service name, and it returns the reference to service object. Such that we can invoke method, access properties etc on the service object. You may have question whether you can also put properties, methods on scope object of controllers! So why you need service object? Answers is: services are shared among multiple controller scope. If you put some properties/methods in a controller's scope object , it will be available to current scope only. But when you define methods, properties on service object, it will be available globally and can be accessed in any controller's scope by injecting that service.

So if there are three controller scope, let it be controllerA, controllerB and controllerC, all will share same service instance.

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

How to create a service?

AngularJS provide different methods to register a service. Here we will concentrate on three methods factory(..),service(..),provider(..);

Use this link for code reference

Factory function:

We can define a factory function as below.

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

AngularJS provides 'factory('serviceName', fnFactory)' method which takes two parameter, serviceName and a JavaScript function. Angular creates service instance by invoking the function fnFactory() such as below.

var serviceInstace = fnFactory();

The passed function can define a object and return that object. AngularJS simply stores this object reference to a variable which is passed as first argument. Anything which is returned from fnFactory will be bound to serviceInstance . Instead of returning object , we can also return function, values etc, Whatever we will return , will be available to service instance.

Example:

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

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

It's the another way, we can register a service. The only difference is the way AngularJS tries to instantiate the service object. This time angular uses 'new' keyword and call the constructor function something like below.

var serviceInstance = new fnServiceConstructor();

In the constructor function we can use 'this' keyword for adding properties/methods to the service object. example:

//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 function:

Provider() function is the another way for creating services. Let we are interested to create a service which just display some greeting message to the user. But we also want to provide a functionality such that user can set their own greeting message. In technical terms we want to create configurable services. How can we do this ? There must be a way, so that app could pass their custom greeting messages and Angularjs would make it available to factory/constructor function which create our services instance. In such a case provider() function do the job. using provider() function we can create configurable services.

We can create configurable services using provider syntax as given below.

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

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

How does provider syntax internally work?

1.Provider object is created using constructor function we defined in our provider function.

var serviceProvider = new serviceProviderConstructor();

2.The function we passed in app.config(), get executed. This is called config phase, and here we have a chance to customize our service.

configureService(serviceProvider);

3.Finally service instance is created by calling $get method of serviceProvider.

serviceInstance = serviceProvider.$get()

Sample code for creating service using provide syntax:

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

Working Demo

Summary:


Factory use a factory function which return a service instance. serviceInstance = fnFactory();

Service use a constructor function and Angular invoke this constructor function using 'new' keyword for creating the service instance. serviceInstance = new fnServiceConstructor();

Provider defines a providerConstructor function, this providerConstructor function defines a factory function $get . Angular calls $get() to create the service object. Provider syntax has an added advantage of configuring the service object before it get instantiated. serviceInstance = $get();


133



As pointed out by several people here correctly a factory, provider, service, and even value and constant are versions of the same thing. You can dissect the more general provider into all of them. Like so:

enter image description here

Here's the article this image is from:

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


78



Factory

You give AngularJS a function, AngularJS will cache and inject the return value when the factory is requested.

Example:

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

Usage:

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

Service

You give AngularJS a function, AngularJS will call new to instantiate it. It is the instance that AngularJS creates that will be cached and injected when the service is requested. Since new was used to instantiate the service, the keyword this is valid and refers to the instance.

Example:

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

Usage:

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

Provider

You give AngularJS a function, and AngularJS will call its $get function. It is the return value from the $get function that will be cached and injected when the service is requested.

Providers allow you to configure the provider before AngularJS calls the $get method to get the injectible.

Example:

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

Usage (as an injectable in a controller)

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

Usage (configuring the provider before $get is called to create the injectable)

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

62