Quais são as diferenças entre um Service
, Provider
e Factory
em AngularJS?
service.factory
. Não queria complicar ainda mais esse assunto.
Quais são as diferenças entre um Service
, Provider
e Factory
em AngularJS?
service.factory
. Não queria complicar ainda mais esse assunto.
Respostas:
Na lista de discussão do AngularJS, recebi uma discussão incrível que explica serviço x fábrica x provedor e seu uso de injeção. Compilando as respostas:
Sintaxe: module.service( 'serviceName', function );
Resultado: Ao declarar serviceName como um argumento injetável, você receberá uma instância da função. Em outras palavras new FunctionYouPassedToService()
.
Sintaxe: module.factory( 'factoryName', function );
Resultado: Ao declarar factoryName como um argumento injetável, você receberá o valor retornado invocando a referência de função passada para module.factory .
Sintaxe: module.provider( 'providerName', function );
Resultado: Ao declarar providerName como um argumento injetável, você será fornecido (new ProviderFunction()).$get()
. A função construtora é instanciada antes que o método $ get seja chamado - ProviderFunction
é a referência da função passada para module.provider.
Os fornecedores têm a vantagem de poderem ser configurados durante a fase de configuração do módulo.
Veja aqui o código fornecido.
Aqui está uma grande explicação adicional de Misko:
provide.value('a', 123);
function Controller(a) {
expect(a).toEqual(123);
}
Nesse caso, o injetor simplesmente retorna o valor como está. Mas e se você quiser calcular o valor? Então use uma fábrica
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
Assim factory
é uma função que é responsável por criar o valor. Observe que a função de fábrica pode solicitar outras dependências.
Mas e se você quiser ter mais OO e ter uma classe chamada Greeter?
function Greeter(a) {
this.greet = function() {
return 'Hello ' + a;
}
}
Então, para instanciar, você teria que escrever
provide.factory('greeter', function(a) {
return new Greeter(a);
});
Então poderíamos pedir 'greeter' em um controlador como este
function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual('Hello 123');
}
Mas isso é muito prolixo. Uma maneira mais curta de escrever isso seriaprovider.service('greeter', Greeter);
Mas e se quiséssemos configurar a Greeter
classe antes da injeção? Então poderíamos escrever
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);
};
});
Então podemos fazer isso:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
Como uma nota lateral, service
, factory
, e value
são todos derivados do provedor.
provider.service = function(name, Class) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.instantiate(Class);
};
});
}
provider.factory = function(name, factory) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.invoke(factory);
};
});
}
provider.value = function(name, value) {
provider.factory(name, function() {
return value;
});
};
toEqual
e greeter.Greet
é. Por que não usar algo um pouco mais real e relacionável?
factory
/ service
/ provider
:var myApp = angular.module('myApp', []);
//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
//provider style, full blown, configurable version
myApp.provider('helloWorld', function() {
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "!";
}
}
};
this.setName = function(name) {
this.name = name;
};
});
//hey, we can configure a provider!
myApp.config(function(helloWorldProvider){
helloWorldProvider.setName('World');
});
function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
$scope.hellos = [
helloWorld.sayHello(),
helloWorldFromFactory.sayHello(),
helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
{{hellos}}
</div>
</body>
this
muda o contexto na $get
função? - você não se refere mais ao provedor instanciado nessa função.
this
não muda o contexto, na verdade, porque o que está sendo chamado é new Provider()
. $ Get (), para onde Provider
a função está sendo passada app.provider
. Ou seja, $get()
está sendo chamado como método no construído Provider
, portanto, this
será referido Provider
como o exemplo sugere.
Unknown provider: helloWorldProvider <- helloWorld
ao executar isso localmente? Comentando, o mesmo erro para os outros 2 exemplos. Existe alguma configuração de provedor oculto? (Angular 1.0.8) - Encontrado: stackoverflow.com/questions/12339272/…
TL; DR
1) Ao usar um Factory, você cria um objeto, adiciona propriedades a ele e retorna o mesmo objeto. Quando você passar esta fábrica para o seu controlador, essas propriedades no objeto estarão agora disponíveis nesse controlador através da sua fábrica.
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) Ao usar o Serviço , o AngularJS o instancia nos bastidores com a palavra-chave 'new'. Por isso, você adicionará propriedades a 'this' e o serviço retornará 'this'. Quando você passa o serviço para o seu controlador, essas propriedades agora estarão disponíveis nesse controlador através do seu serviço.
app.controller(‘myServiceCtrl’, function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service(‘myService’, function(){
var _artist = ‘Nelly’;
this.getArtist = function(){
return _artist;
}
});
3) Os provedores são o único serviço que você pode transmitir para a função .config (). Use um provedor quando desejar fornecer configuração em todo o módulo para seu objeto de serviço antes de disponibilizá-lo.
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’;
});
Não TL; DR
1)
Fábricas de fábrica são a maneira mais popular de criar e configurar um serviço. Realmente não há muito mais do que o TL; DR disse. Você acabou de criar um objeto, adicionar propriedades a ele e retornar o mesmo objeto. Então, quando você passar a fábrica para o seu controlador, essas propriedades no objeto estarão agora disponíveis nesse controlador através da sua fábrica. Um exemplo mais extenso está abaixo.
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
Agora, quaisquer propriedades que anexarmos a 'service' estarão disponíveis quando passarmos 'myFactory' para o nosso controlador.
Agora vamos adicionar algumas variáveis 'privadas' à nossa função de retorno de chamada. Eles não estarão diretamente acessíveis no controlador, mas, eventualmente, configuraremos alguns métodos getter / setter no 'service' para poder alterar essas variáveis 'privadas' quando necessário.
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;
});
Aqui você notará que não estamos anexando essas variáveis / funções ao 'serviço'. Estamos simplesmente criando-os para usá-los ou modificá-los posteriormente.
Agora que nossas variáveis e funções auxiliares / particulares estão em vigor, vamos adicionar algumas propriedades ao objeto 'service'. Tudo o que colocamos em 'serviço' pode ser usado diretamente dentro de qualquer controlador no qual passamos 'myFactory'.
Vamos criar métodos setArtist e getArtist que simplesmente retornam ou definem o artista. Também vamos criar um método que chamará a API do iTunes com nosso URL criado. Esse método retornará uma promessa que será cumprida assim que os dados voltarem da API do iTunes. Se você não teve muita experiência no uso de promessas no AngularJS, recomendo fazer um mergulho profundo nelas.
Abaixo, o setArtist aceita um artista e permite que você o defina. O getArtist retorna o artista. O callItunes chama primeiro makeUrl () para criar o URL que usaremos com nossa solicitação $ http. Em seguida, ele configura um objeto de promessa, faz uma solicitação $ http com nosso URL final e, como $ http retorna uma promessa, podemos chamar .success ou .error após nossa solicitação. Em seguida, resolvemos nossa promessa com os dados do iTunes ou a rejeitamos com uma mensagem dizendo 'Houve um erro'.
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;
});
Agora nossa fábrica está completa. Agora podemos injetar 'myFactory' em qualquer controlador e, em seguida, poderemos chamar nossos métodos que anexamos ao nosso objeto de serviço (setArtist, getArtist e 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);
})
}
});
No controlador acima, estamos injetando no serviço 'myFactory'. Em seguida, definimos propriedades em nosso objeto $ scope com dados de 'myFactory'. O único código complicado acima é se você nunca lidou com promessas antes. Como o callItunes está retornando uma promessa, podemos usar o método .then () e definir apenas $ scope.data.artistData quando nossa promessa for cumprida com os dados do iTunes. Você notará que nosso controlador é muito 'fino' (esta é uma boa prática de codificação). Todos os nossos dados lógicos e persistentes estão localizados em nosso serviço, não em nosso controlador.
2) Serviço
Talvez a maior coisa a saber quando se lida com a criação de um Serviço é que ele é instanciado com a palavra-chave 'new'. Para os gurus do JavaScript, isso deve fornecer uma grande dica sobre a natureza do código. Para aqueles com conhecimentos limitados em JavaScript ou para aqueles que não conhecem muito bem o que a palavra-chave 'new' realmente faz, vamos revisar alguns fundamentos do JavaScript que eventualmente nos ajudarão a entender a natureza de um Serviço.
Para realmente ver as alterações que ocorrem quando você invoca uma função com a palavra-chave 'new', vamos criar uma função e invocá-la com a palavra-chave 'new', depois vamos mostrar o que o intérprete faz quando vê a palavra-chave 'new'. Os resultados finais serão os mesmos.
Primeiro, vamos criar nosso Construtor.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Essa é uma função típica do construtor JavaScript. Agora, sempre que invocarmos a função Pessoa usando a palavra-chave 'new', 'this' será vinculado ao objeto recém-criado.
Agora, vamos adicionar um método ao protótipo de nossa Person, para que fique disponível em todas as instâncias da nossa classe de Person.
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
Agora, como colocamos a função sayName no protótipo, todas as instâncias de Person poderão chamar a função sayName para alertar o nome dessa instância.
Agora que temos nossa função construtora Person e nossa função sayName em seu protótipo, vamos criar uma instância de Person e chamar a função sayName.
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
Portanto, todo o código para criar um construtor Person, adicionar uma função a seu protótipo, criar uma instância Person e chamar a função em seu protótipo se parece com isso.
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’
Agora, vamos ver o que realmente está acontecendo quando você usa a palavra-chave 'new' em JavaScript. A primeira coisa que você deve notar é que, depois de usar 'new' em nosso exemplo, podemos chamar um método (sayName) em 'tyler' como se fosse um objeto - é porque é. Então, primeiro, sabemos que nosso construtor Person está retornando um objeto, se podemos ver isso no código ou não. Segundo, sabemos que, como nossa função sayName está localizada no protótipo e não diretamente na instância Person, o objeto que a função Person está retornando deve delegar ao seu protótipo em pesquisas com falha. Em termos mais simples, quando chamamos tyler.sayName (), o intérprete diz: “OK, vou olhar para o objeto 'tyler' que acabamos de criar, localize a função sayName e chame-a. Espere um minuto, não o vejo aqui - tudo o que vejo é nome e idade, deixe-me verificar o protótipo. Sim, parece que está no protótipo, deixe-me chamá-lo. ”.
Abaixo está o código de como você pode pensar sobre o que a palavra-chave 'nova' está realmente fazendo em JavaScript. É basicamente um exemplo de código do parágrafo acima. Coloquei a 'visão do intérprete' ou a maneira como o intérprete vê o código dentro das notas.
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;
}
Agora, tendo esse conhecimento do que a palavra-chave 'new' realmente faz em JavaScript, a criação de um Serviço no AngularJS deve ser mais fácil de entender.
A principal coisa a entender ao criar um Serviço é saber que os Serviços são instanciados com a palavra-chave 'new'. Combinando esse conhecimento com nossos exemplos acima, você deve reconhecer agora que anexará suas propriedades e métodos diretamente a 'this', que serão devolvidos pelo próprio Serviço. Vamos dar uma olhada nisso em ação.
Diferentemente do que fizemos originalmente com o exemplo do Factory, não precisamos criar um objeto e, em seguida, retorná-lo, porque, como mencionado muitas vezes antes, usamos a palavra-chave 'new' para que o intérprete crie esse objeto, faça-o delegar para é protótipo e, em seguida, devolva-o para nós sem que tenhamos que fazer o trabalho.
Primeiramente, vamos criar nossa função 'privada' e auxiliar. Isso deve parecer muito familiar, já que fizemos exatamente a mesma coisa com nossa fábrica. Não vou explicar o que cada linha faz aqui, porque fiz isso no exemplo de fábrica; se você estiver confuso, releia o exemplo de fábrica.
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;
}
});
Agora, anexaremos todos os nossos métodos que estarão disponíveis em nosso controlador a 'this'.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.setArtist = function(artist){
_artist = artist;
}
this.getArtist = function(){
return _artist;
}
this.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
});
Agora, assim como em nossa fábrica, setArtist, getArtist e callItunes estarão disponíveis em qualquer controlador em que passarmos o myService. Aqui está o controlador myService (que é quase exatamente o mesmo que o nosso controlador de fábrica).
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);
})
}
});
Como mencionei antes, quando você realmente entende o que 'novo' faz, os Serviços são quase idênticos às fábricas no AngularJS.
3) Fornecedor
A principal coisa a lembrar sobre os Provedores é que eles são o único serviço que você pode passar para a parte app.config do seu aplicativo. Isso é de grande importância se você precisar alterar parte do objeto de serviço antes que ele esteja disponível em qualquer outro lugar do aplicativo. Embora muito parecido com Serviços / Fábricas, existem algumas diferenças que discutiremos.
Primeiro, configuramos nosso provedor de maneira semelhante ao nosso serviço e fábrica. As variáveis abaixo são nossa função 'privada' e auxiliar.
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;
}
}
* Novamente, se qualquer parte do código acima estiver confusa, consulte a seção Factory, onde explico o que isso faz com mais detalhes.
Você pode pensar em Provedores como tendo três seções. A primeira seção são as variáveis / funções 'particulares' que serão modificadas / definidas posteriormente (mostradas acima). A segunda seção são as variáveis / funções que estarão disponíveis na função app.config e, portanto, estão disponíveis para alteração antes de estarem disponíveis em qualquer outro lugar (também mostrado acima). É importante observar que essas variáveis precisam ser anexadas à palavra-chave 'this'. No nosso exemplo, apenas 'thingFromConfig' estará disponível para alteração no app.config. A terceira seção (mostrada abaixo) são todas as variáveis / funções que estarão disponíveis no seu controlador quando você passar o serviço 'myProvider' para esse controlador específico.
Ao criar um serviço com o Provedor, as únicas propriedades / métodos que estarão disponíveis no seu controlador são as propriedades / métodos retornados da função $ get (). O código abaixo coloca $ get on 'this' (que sabemos que eventualmente serão retornados dessa função). Agora, essa função $ get retorna todos os métodos / propriedades que queremos que estejam disponíveis no controlador. Aqui está um exemplo de código.
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
}
}
Agora, o código completo do provedor se parece com isso
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
}
}
});
Agora, assim como em nossa fábrica e Serviço, setArtist, getArtist e callItunes estarão disponíveis em qualquer controlador em que passarmos o myProvider. Aqui está o controlador myProvider (que é quase exatamente o mesmo que o nosso controlador de fábrica / serviço).
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;
});
Como mencionado anteriormente, o objetivo principal de criar um serviço com o Provedor é poder alterar algumas variáveis por meio da função app.config antes que o objeto final seja passado para o restante do aplicativo. Vamos ver um exemplo disso.
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';
});
Agora você pode ver como 'thingFromConfig' é uma string vazia no nosso provedor, mas quando isso aparecer no DOM, será 'Esta frase foi configurada ...'.
Todos os serviços são singletons ; eles são instanciados uma vez por aplicativo. Eles podem ser de qualquer tipo , seja um primitivo, literal de objeto, função ou até uma instância de um tipo personalizado.
O value
,factory
, service
, constant
, e provider
métodos são todos os provedores. Eles ensinam ao Injetor como instanciar os Serviços.
A mais detalhada, mas também a mais abrangente, é uma receita de Provedor. Os quatro restantes tipos de receita - Valor, Fábrica, Serviço e Constante - são apenas açúcar sintático em cima de uma receita de provedor .
Você deve usar a receita do provedor apenas quando quiser expor uma API para a configuração de todo o aplicativo que deve ser feita antes do aplicativo ser iniciado. Isso geralmente é interessante apenas para serviços reutilizáveis cujo comportamento pode precisar variar um pouco entre aplicativos.
decorator
.Compreendendo o AngularJS Factory, Service and Provider
Tudo isso é usado para compartilhar objetos singleton reutilizáveis. Ajuda a compartilhar código reutilizável em seu aplicativo / vários componentes / módulos.
No Docs Service / Factory :
- Instanciado preguiçosamente - o Angular apenas instancia um serviço / fábrica quando um componente de aplicativo depende dele.
- Singletons - Cada componente dependente de um serviço obtém uma referência à instância única gerada pela fábrica de serviços.
Uma fábrica é uma função na qual você pode manipular / adicionar lógica antes de criar um objeto, para que o objeto recém-criado seja retornado.
app.factory('MyFactory', function() {
var serviceObj = {};
//creating an object with methods/functions or variables
serviceObj.myFunction = function() {
//TO DO:
};
//return that object
return serviceObj;
});
Uso
Pode ser apenas uma coleção de funções como uma classe. Portanto, ele pode ser instanciado em diferentes controladores quando você o injeta nas funções de controlador / fábrica / diretiva. É instanciado apenas uma vez por aplicativo.
Simplesmente enquanto olha para os serviços, pense no protótipo da matriz. Um serviço é uma função que instancia um novo objeto usando a palavra-chave 'new'. Você pode adicionar propriedades e funções a um objeto de serviço usando a this
palavra - chave Ao contrário de uma fábrica, ele não retorna nada (retorna um objeto que contém métodos / propriedades).
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
Uso
Use-o quando precisar compartilhar um único objeto em todo o aplicativo. Por exemplo, detalhes do usuário autenticado, métodos / dados compartilhados, funções do utilitário etc.
Um provedor é usado para criar um objeto de serviço configurável. Você pode definir a configuração de serviço na função de configuração. Retorna um valor usando a $get()
função A $get
função é executada na fase de execução em 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.
};
};
});
Uso
Quando você precisar fornecer configuração em módulo para o seu objeto de serviço antes de disponibilizá-lo, por exemplo. suponha que você queira definir o URL da API com base no seu ambiente dev
, como , stage
ouprod
NOTA
Somente o provedor estará disponível na fase de configuração angular, enquanto o serviço e a fábrica não estiverem.
Espero que isso tenha esclarecido sua compreensão sobre a fábrica, o serviço e o fornecedor .
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
, então não parece possível, certo?
Para mim, a revelação veio quando percebi que todos eles funcionam da mesma maneira: executando algo uma vez , armazenando o valor que recebem e depois tossindo esse mesmo valor armazenado quando referenciado por injeção de dependência .
Digamos que temos:
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
A diferença entre os três é que:
a
O valor armazenado de vem da execução fn
.b
O valor armazenado vem de new
ingfn
.c
O valor armazenado é obtido primeiro pela obtenção de uma instância new
ing fn
e, em seguida, pela execução de um $get
método da instância.O que significa que há algo como um objeto de cache dentro do AngularJS, cujo valor de cada injeção é atribuído apenas uma vez, quando foram injetados pela primeira vez e onde:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
É por isso que usamos this
em serviços e definimos um this.$get
em provedores.
factory
s. Os únicos motivos pelos quais service
existem são linguagens como CoffeeScript, TypeScript, ES6 etc., para que você possa usar a sintaxe da classe. Você precisa provider
apenas se seu módulo for usado em vários aplicativos com configurações diferentes usando app.config()
. Se o seu serviço for um singleton puro ou for capaz de criar instâncias de algo, isso depende apenas da sua implementação.
Serviço x fornecedor x fábrica:
Estou tentando simplificar. É tudo sobre o conceito básico de JavaScript.
Primeiro de tudo, vamos falar sobre serviços no AngularJS!
O que é serviço: no AngularJS, serviçonada mais é que um objeto JavaScript singleton que pode armazenar alguns métodos ou propriedades úteis. Esse objeto singleton é criado por ngApp (aplicativo Angular) e é compartilhado entre todos os controladores no aplicativo atual. Quando o Angularjs instancia um objeto de serviço, ele registra esse objeto de serviço com um nome de serviço exclusivo. Portanto, sempre que precisamos de uma instância de serviço, o Angular pesquisa no registro esse nome de serviço e retorna a referência ao objeto de serviço. Para que possamos chamar método, acessar propriedades etc. no objeto de serviço. Você pode ter dúvidas se também pode colocar propriedades, métodos no escopo objeto dos controladores! Então, por que você precisa de objeto de serviço? As respostas são: os serviços são compartilhados entre vários escopos de controladores. Se você colocar algumas propriedades / métodos no objeto de escopo de um controlador, ele estará disponível apenas no escopo atual.
Portanto, se houver três escopos de controlador, sejam controllerA, controllerB e controllerC, todos compartilharão a mesma instância de serviço.
<div ng-controller='controllerA'>
<!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
<!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
<!-- controllerC scope -->
</div>
Como criar um serviço?
O AngularJS fornece métodos diferentes para registrar um serviço. Aqui vamos nos concentrar em três métodos: fábrica (..), serviço (..), provedor (..);
Use este link para referência de código
Podemos definir uma função de fábrica como abaixo.
factory('serviceName',function fnFactory(){ return serviceInstance;})
O AngularJS fornece o método 'factory (' serviceName ', fnFactory)' que utiliza dois parâmetros, serviceName e uma função JavaScript. Angular cria instância de serviço chamando a função fnFactory () como abaixo.
var serviceInstace = fnFactory();
A função passada pode definir um objeto e retornar esse objeto. O AngularJS simplesmente armazena essa referência de objeto em uma variável que é passada como primeiro argumento. Tudo o que for retornado do fnFactory será vinculado ao serviceInstance. Em vez de retornar o objeto, também podemos retornar funções, valores, etc. O que retornarmos estará disponível para a instância de serviço.
Exemplo:
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(){})
Por outro lado, podemos registrar um serviço. A única diferença é a maneira como o AngularJS tenta instanciar o objeto de serviço. Desta vez, o angular usa a palavra-chave 'new' e chama a função construtora como algo abaixo.
var serviceInstance = new fnServiceConstructor();
Na função construtora, podemos usar a palavra-chave 'this' para adicionar propriedades / métodos ao objeto de serviço. exemplo:
//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);
};
});
A função Provider () é a outra maneira de criar serviços. Vamos nos interessar em criar um serviço que apenas exiba alguma mensagem de saudação ao usuário. Mas também queremos fornecer uma funcionalidade para que o usuário possa definir sua própria mensagem de saudação. Em termos técnicos, queremos criar serviços configuráveis. Como podemos fazer isso ? Deve haver uma maneira de que o aplicativo possa transmitir suas mensagens de saudação personalizadas e o Angularjs disponibilizá-lo para a função de fábrica / construtor que cria nossa instância de serviços. Nesse caso, a função provider () faz o trabalho. usando a função provider (), podemos criar serviços configuráveis.
Podemos criar serviços configuráveis usando a sintaxe do provedor, conforme indicado abaixo.
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
O objeto 1.Provider é criado usando a função construtora que definimos em nossa função de provedor.
var serviceProvider = new serviceProviderConstructor();
2.A função que passamos em app.config () é executada. Isso é chamado de fase de configuração, e aqui temos a chance de personalizar nosso serviço.
configureService(serviceProvider);
3. Finalmente, a instância de serviço é criada chamando o método $ get de 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 ?');
}
);
Resumo:
Fábrica use uma função de fábrica que retorne uma instância de serviço. serviceInstance = fnFactory ();
O serviço usa uma função construtora e o Angular invoca essa função construtora usando a palavra-chave 'new' para criar a instância do serviço. serviceInstance = novo fnServiceConstructor ();
O provedor define uma função providerConstructor, essa função providerConstructor define uma função de fábrica $ get . Chamadas angulares $ get () para criar o objeto de serviço. A sintaxe do provedor tem uma vantagem adicional de configurar o objeto de serviço antes que ele seja instanciado. serviceInstance = $ get ();
Como apontado por várias pessoas aqui corretamente, fábrica, provedor, serviço e até valor e constante são versões da mesma coisa. Você pode dissecar o mais geral provider
em todos eles. Igual a:
Aqui está o artigo desta imagem:
Você atribui uma função ao AngularJS, o AngularJS armazenará em cache e injetará o valor de retorno quando a fábrica for solicitada.
Exemplo:
app.factory('factory', function() {
var name = '';
// Return value **is** the object that will be injected
return {
name: name;
}
})
Uso:
app.controller('ctrl', function($scope, factory) {
$scope.name = factory.name;
});
Você atribui uma função ao AngularJS, o AngularJS chamará new para instancia-lo. É a instância criada pelo AngularJS que será armazenada em cache e injetada quando o serviço for solicitado. Como new foi usado para instanciar o serviço, a palavra - chave é válida e refere-se à instância.
Exemplo:
app.service('service', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.getName = function() {
return name;
}
});
Uso:
app.controller('ctrl', function($scope, service) {
$scope.name = service.getName();
});
Você atribui uma função ao AngularJS e o AngularJS chamará sua $get
função. É o valor de retorno da $get
função que será armazenado em cache e injetado quando o serviço for solicitado.
Os provedores permitem que você configure o provedor antes que o AngularJS chame o $get
método para obter o injetável.
Exemplo:
app.provider('provider', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.$get = function() {
return {
name: name
}
}
})
Uso (como um injetável em um controlador)
app.controller('ctrl', function($scope, provider) {
$scope.name = provider.name;
});
Uso (a configuração do provedor anterior $get
é chamada para criar o injetável)
app.config(function(providerProvider) {
providerProvider.setName('John');
});
Notei algo interessante ao brincar com os provedores.
A visibilidade dos injetáveis é diferente para os fornecedores e para os serviços e fábricas. Se você declarar uma "constante" AngularJS (por exemplo,myApp.constant('a', 'Robert');
), poderá injetá-la em serviços, fábricas e fornecedores.
Mas se você declarar um "valor" do AngularJS (por exemplo., myApp.value('b', {name: 'Jones'});
), Poderá injetá-lo em serviços e fábricas, mas NÃO na função de criação de provedor. No entanto, você pode injetá-lo na $get
função que você define para o seu provedor. Isso é mencionado na documentação do AngularJS, mas é fácil perder. Você pode encontrá-lo na página% de fornecimento nas seções sobre métodos de valor e constante.
<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>
Esta é uma parte muito confusa para o novato e tentei esclarecê-lo com palavras fáceis
Serviço AngularJS: é usado para compartilhar funções de utilitário com a referência de serviço no controlador. O serviço é de natureza única, portanto, para um serviço, apenas uma instância é criada no navegador e a mesma referência é usada em toda a página.
No serviço, criamos nomes de função como propriedade com este objeto.
AngularJS Factory: o objetivo do Factory também é o mesmo do Service, no entanto, neste caso, criamos um novo objeto e adicionamos funções como propriedades desse objeto e, no final, retornamos esse objeto.
Provedor AngularJS: o objetivo disso é novamente o mesmo, no entanto, o Provedor fornece a saída de sua função $ get.
A definição e o uso de Serviço, Fábrica e Fornecedor são explicados em http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider
Para mim, a melhor e a maneira mais simples de entender a diferença é:
var service, factory;
service = factory = function(injection) {}
Como o AngularJS instancia componentes específicos (simplificado):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
Portanto, para o serviço, o que se torna o componente AngularJS é a instância do objeto da classe que é representada pela função de declaração de serviço. Para a fábrica, é o resultado retornado da função de declaração de fábrica. A fábrica pode se comportar da mesma maneira que o serviço:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
A maneira mais simples de pensar é a seguinte:
O exemplo de 'classe' de fábrica é fornecido nos comentários, bem como a diferença de fornecedor.
new MyService()
ou algo :)
Meu esclarecimento sobre este assunto:
Basicamente, todos os tipos mencionados (serviço, fábrica, provedor etc.) estão apenas criando e configurando variáveis globais (que são obviamente globais para todo o aplicativo), exatamente como eram as variáveis globais antiquadas.
Embora as variáveis globais não sejam recomendadas, o uso real dessas variáveis globais é fornecer injeção de dependência , passando a variável para o controlador relevante.
Existem muitos níveis de complicações na criação dos valores para as "variáveis globais":
app.config
.
app.config
arquivo, e essa função $ .get se comporta exatamente como a fábrica acima, em que seu valor de retorno é usado para inicializar as variáveis "globais". Meu entendimento é muito simples abaixo.
Fábrica: você simplesmente cria um objeto dentro da fábrica e o devolve.
Serviço:
Você apenas tem uma função padrão que usa essa palavra-chave para definir uma função.
Fornecedor:
Há um $get
objeto que você define e pode ser usado para obter o objeto que retorna dados.
Resumo dos documentos angulares :
Melhores respostas de SO:
https://stackoverflow.com/a/26924234/165673 (<- GOOD)
https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673
Todas as boas respostas já. Gostaria de acrescentar mais alguns pontos sobre Serviço e Fábrica . Junto com a diferença entre serviço / fábrica. E também se pode ter perguntas como:
Vamos começar com a diferença entre serviço e fábrica:
Ambos são singletons : sempre que o Angular os encontra como dependência pela primeira vez, ele cria uma única instância de serviço / fábrica. Depois que a instância é criada, a mesma instância é usada para sempre.
Pode ser usado para modelar um objeto com comportamento : ambos podem ter métodos, variáveis de estado interno e assim por diante. Embora a maneira como você escreve esse código seja diferente.
Serviços:
Um serviço é uma função construtora, e o Angular irá instancia-lo chamando new yourServiceName()
. Isso significa algumas coisas.
this
.new yourServiceName(
), ele recebe o this
objeto com todas as propriedades que você coloca nele.Exemplo de exemplo:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
Quando o Angular injeta esse
MyService
serviço em um controlador que depende dele, esse controlador recebe umMyService
que pode chamar funções, por exemplo, MyService.aServiceMethod ().
Seja cuidadoso com this
:
Como o serviço construído é um objeto, os métodos dentro dele podem se referir a isso quando são chamados:
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++;
};
});
Você pode ficar tentado a entrar ScoreKeeper.setScore
em uma cadeia de promessas, por exemplo, se inicializou a pontuação pegando-a no servidor: $http.get('/score').then(ScoreKeeper.setScore).
O problema é que ScoreKeeper.setScore
será chamado com this
vinculado null
e você obterá erros. A melhor maneira seria $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))
. Se você optar por usar isso em seus métodos de serviço ou não, tome cuidado com a forma como os chama.
Retornando um valor deService
:
Devido à maneira como os construtores JavaScript funcionam, se você retornar um valor complexo (i.e., an Object)
de uma constructor
função, o chamador obterá esse Objeto em vez da instância.
Isso significa que você pode basicamente copiar e colar o exemplo de fábrica abaixo, substituir factory
por service
e ele funcionará:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
Portanto, quando Angular constrói seu serviço com o novo MyService (), ele obtém esse objeto api em vez da instância do MyService.
Esse é o comportamento para quaisquer valores complexos (objetos, funções), mas não para tipos primitivos.
Fábricas:
Uma fábrica é uma função antiga simples que retorna um valor. O valor de retorno é o que é injetado em coisas que dependem da fábrica. Um padrão de fábrica típico em Angular é retornar um objeto com funções como propriedades, assim:
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
O valor injetado para uma dependência de fábrica é o valor de retorno da fábrica e não precisa ser um objeto. Poderia ser uma função
Respostas para as perguntas 1 e 2 acima:
Na maioria das vezes, continue usando fábricas para tudo. O comportamento deles é mais fácil de entender. Não há escolha a fazer sobre retornar ou não um valor e, além disso, não há bugs a serem introduzidos se você fizer a coisa errada.
Ainda me refiro a eles como "serviços" quando estou falando de injetá-los como dependências.
O comportamento do serviço / fábrica é muito semelhante e algumas pessoas dizem que qualquer um deles está bem. Isso é verdade, mas acho mais fácil seguir os conselhos do guia de estilo de John Papa e permanecer nas fábricas. **
Um esclarecimento adicional é que as fábricas podem criar funções / primitivas, enquanto os serviços não. Verifique este jsFiddle com base no Epokk: http://jsfiddle.net/skeller88/PxdSP/1351/ .
A fábrica retorna uma função que pode ser chamada:
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
A fábrica também pode retornar um objeto com um método que pode ser chamado:
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
O serviço retorna um objeto com um método que pode ser chamado:
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
Para obter mais detalhes, consulte um post que escrevi sobre a diferença: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/
Já existem boas respostas, mas só quero compartilhar essa.
Primeiro de tudo: o provedor é o caminho / receita para criar umservice
(objeto singleton) que deve ser injetado pelo $ injector (como o AngulaJS segue o padrão de IoC).
E Valor, Fábrica, Serviço e Constante (4 vias) - o açúcar sintático sobre a maneira / recebimento do Fornecedor .
Não é Service vs Factory
parte foi coberta:
https://www.youtube.com/watch?v=BLzNCkPn3ao
O serviço tem tudo a ver com new
palavras-chave, que, como sabemos, fazem quatro coisas:
prototype
objetocontext
athis
this
E Factory é tudo sobre Factory Pattern - contém funções que retornam objetos como esse serviço.
E este vídeo simples / curto: abrange também o provedor : https://www.youtube.com/watch?v=HvTZbQ_hUZY (lá você pode ver como eles vão da fábrica para o fornecedor)
A receita do provedor é usada principalmente na configuração do aplicativo, antes que o aplicativo seja totalmente iniciado / inicializado.
Depois de ler todos esses posts, criou mais confusão para mim .. Mas ainda assim tudo é informação valiosa .. finalmente encontrei a tabela a seguir que dará informações com comparação simples
E, para iniciantes, entenda: - Isso pode não corrigir o caso de uso, mas em alto nível é o que usamos para esses três.
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
Para cenários básicos, a fábrica e o serviço se comportam da mesma maneira.
Aqui está um código que eu criei como um modelo de código para a fábrica de objetos no AngularjS. Eu usei um Car / CarFactory como exemplo para ilustrar. Cria um código de implementação simples no controlador.
<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>
Aqui está um exemplo mais simples. Estou usando algumas bibliotecas de terceiros que esperam um objeto "Posição" expondo latitude e longitude, mas através de diferentes propriedades do objeto. Como não queria invadir o código do fornecedor, ajustei os objetos "Posição" que estava passando.
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
;
Usando como referência esta página e a documentação (que parece ter melhorado muito desde a última vez que procurei), montei a seguinte demonstração do mundo real (-ish) que usa quatro dos cinco tipos de provedor; Valor, constante, fábrica e fornecedor completo.
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>
aplicativo
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);
};
});
Demonstração de trabalho .
Esta resposta aborda o tópico / pergunta
OU
basicamente o que acontece é
Quando você factory()
cria um conjunto de configurações function
fornecido no segundo argumento para o provedor $get
e o retorna ( provider(name, {$get:factoryFn })
), tudo o que você obtém é que provider
não há nenhuma propriedade / método além$get
disso provider
(significa que você não pode configurar isso)
Código fonte da fábrica
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
Ao fazer um service()
retorno, você fornece a uma fábrica () um function
que injeta constructor
(retorna a instância do construtor que você forneceu em seu serviço) e o devolve
Código fonte de serviço
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
Então, basicamente, em ambos os casos, você eventualmente obtém um conjunto de provedores $ definido para sua função que você forneceu, mas você pode fornecer algo a mais que $ get, como você pode fornecer originalmente no provedor () para o bloco de configuração
Conheço muitas respostas excelentes, mas tenho que compartilhar minha experiência de usar
1. service
na maioria dos casos de padrão
2. factory
usado para criar o serviço nessa instância específica
// 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){ ...
}
}
})();
e usando:
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;
...
Um pouco tarde para a festa. Mas achei que isso seria mais útil para quem gostaria de aprender (ou ter clareza) sobre o desenvolvimento de serviços personalizados JS angulares usando metodologias de fábrica, serviço e provedor.
Encontrei este vídeo que explica claramente sobre as metodologias de fábrica, serviço e provedor para o desenvolvimento de serviços personalizados do AngularJS:
https://www.youtube.com/watch?v=oUXku28ex-M
Código fonte: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
O código postado aqui é copiado diretamente da fonte acima, para beneficiar os leitores.
O código para o serviço personalizado baseado em "fábrica" é o seguinte (que acompanha as versões de sincronização e assíncrona, além de chamar o serviço 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;
}
]);
O código para a metodologia "service" para serviços personalizados (isso é bastante semelhante ao 'factory', mas diferente do ponto de vista da sintaxe):
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");
});
};
}]);
O código da metodologia "provider" para Serviços Personalizados (isso é necessário, se você desejar desenvolver um serviço que possa ser configurado):
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");
}]);
Finalmente, a interface do usuário que funciona com qualquer um dos serviços acima:
<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>
Apenas para esclarecer as coisas, na fonte AngularJS, você pode ver um serviço que apenas chama a função de fábrica que, por sua vez, chama a função de provedor:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
Vamos discutir as três maneiras de lidar com a lógica de negócios no AngularJS de uma maneira simples: ( Inspirado no curso Coursera AngularJS do Yaakov )
SERVIÇO :
Sintaxe:
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>
Recursos do serviço:
FÁBRICA
Primeiro, vamos dar uma olhada na sintaxe:
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;
}
Agora, usando os dois acima no controlador:
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
Características da fábrica:
.service()
método é uma fábrica que sempre produz o mesmo tipo de serviço, que é um singleton e sem nenhuma maneira fácil de configurar seu comportamento. Esse .service()
método geralmente é usado como um atalho para algo que não requer nenhuma configuração.FORNECEDOR
Vamos novamente dar uma olhada na sintaxe primeiro:
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;
};
}
}
Recursos do Provedor:
.service
ou outro .factory
método.$get
é uma função diretamente anexada à instância do provedor. Essa função é uma função de fábrica . Em outras palavras, é exatamente como o que usamos para fornecer ao .factory
método. Nessa função, criamos nosso próprio serviço. Essa $get
propriedade, que é uma função, é o que torna o provedor um provedor . O AngularJS espera que o provedor tenha uma propriedade $ get cujo valor é uma função que o Angular tratará como uma função de fábrica. Mas o que torna toda essa configuração de provedor muito especial é o fato de podermos fornecer algum config
objeto dentro do provedor de serviços, e isso geralmente vem com padrões que podemos substituir posteriormente na etapa, onde podemos configurar o aplicativo inteiro.Fábrica: a fábrica em que você realmente cria um objeto dentro da fábrica e o devolve.
service: o serviço, você apenas possui uma função padrão que usa a palavra-chave this para definir a função.
provider: O provedor tem um $ get you define e pode ser usado para obter o objeto que retorna os dados.
Essencialmente, Provedor, Fábrica e Serviço são todos Serviços. Um Factory é um caso especial de um Serviço quando tudo o que você precisa é de uma função $ get (), permitindo escrever com menos código.
As principais diferenças entre serviços, fábricas e fornecedores são suas complexidades. Os serviços são a forma mais simples, as fábricas são um pouco mais robustas e os provedores são configuráveis em tempo de execução.
Aqui está um resumo de quando usar cada um:
Fábrica : o valor que você está fornecendo precisa ser calculado com base em outros dados.
Serviço : você está retornando um objeto com métodos.
Fornecedor : você deseja configurar, durante a fase de configuração, o objeto que será criado antes de ser criado. Use o provedor principalmente na configuração do aplicativo, antes que o aplicativo seja totalmente inicializado.
1. Serviços são objetos únicos que são criados quando necessário e nunca são limpos até o final do ciclo de vida do aplicativo (quando o navegador é fechado). Os controladores são destruídos e limpos quando não são mais necessários.
2. A maneira mais fácil de criar um serviço é usando o método factory (). O método factory () nos permite definir um serviço retornando um objeto que contém funções de serviço e dados de serviço. A função de definição de serviço é onde colocamos nossos serviços injetáveis, como $ http e $ q. Ex:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
Usando a factory () em nosso aplicativo
É fácil usar a fábrica em nosso aplicativo, pois podemos simplesmente injetá-lo onde for necessário em tempo de execução.
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});
Açúcar sintático é a diferença . Somente o provedor é necessário. Ou, em outras palavras, apenas o provedor é o angular real, todos os outros são derivados (para reduzir o código). Também existe uma versão simples, chamada Value (), que retorna apenas o valor, sem cálculo ou função. Even Value é derivado do provedor!
Então, por que essas complicações, por que não podemos simplesmente usar o provedor e esquecer todo o resto? Ele deve nos ajudar a escrever código facilmente e nos comunicar melhor. E a resposta direta seria, quanto mais complexo for, melhor será a venda de uma estrutura.
A injeção angular nos dá a primeira dica para chegar a essa conclusão.
"$ injector é usado para recuperar instâncias de objetos, conforme definido pelo provedor " não pelo serviço, não pela fábrica, mas pelo provedor.
E uma resposta melhor seria a seguinte: "Um serviço Angular é criado por uma fábrica de serviços. Essas fábricas de serviços são funções que, por sua vez, são criadas por um provedor de serviços. Os provedores de serviços são funções construtoras. Quando instanciadas, elas devem conter uma propriedade. chamado $ get, que mantém a função da fábrica de serviços ".
Então, o provedor principal e o injetor e tudo se encaixará :). E fica interessante no Typescript quando $ get pode ser implementado em um provedor, herdando do IServiceProvider.