Vi tanto angular.factory () quanto angular.service () usados para declarar serviços; no entanto, não consigo encontrar angular.service
nenhum lugar na documentação oficial.
Qual é a diferença entre os dois métodos?
Qual deve ser usado para quê (supondo que eles façam coisas diferentes)?
angularjs
angular-services
jacob
fonte
fonte
Respostas:
Eu tive problemas para entender esse conceito até colocar para mim mesmo desta maneira:
Serviço : a função que você escreve será nova :
Factory : a função (construtor) que você escreve será chamada :
Depende de você, mas existem alguns padrões úteis ...
Como escrever uma função de serviço para expor uma API pública:
Ou usando uma função de fábrica para expor uma API pública:
Ou usando uma função de fábrica para retornar um construtor:
Qual usar? ...
Você pode realizar a mesma coisa com ambos. No entanto, em alguns casos, a fábrica oferece um pouco mais de flexibilidade para criar um injetável com uma sintaxe mais simples. Isso porque enquanto myInjectedService sempre deve ser um objeto, myInjectedFactory pode ser um objeto, uma referência de função ou qualquer valor. Por exemplo, se você escreveu um serviço para criar um construtor (como no último exemplo acima), ele teria que ser instanciado da seguinte maneira:
que é sem dúvida menos desejável que isso:
(Mas você deve ser cauteloso ao usar esse tipo de padrão em primeiro lugar, porque os novos objetos em seus controladores criam dependências difíceis de rastrear que são difíceis de serem simuladas para teste. É melhor ter um serviço para gerenciar uma coleção de objetos para você do que usar
new()
astuciosamente.)Mais uma coisa, eles são todos Singletons ...
Lembre-se também de que, nos dois casos, angular está ajudando você a gerenciar um singleton. Independentemente de onde ou quantas vezes você injeta seu serviço ou função, você obterá a mesma referência para o mesmo objeto ou função. (Com exceção de quando uma fábrica simplesmente retorna um valor como um número ou sequência. Nesse caso, você sempre obterá o mesmo valor, mas não uma referência.)
fonte
new fn()
, portanto, eles devem retornar uma instância.Basta colocar ..
fonte
Aqui estão as principais diferenças:
Serviços
Sintaxe:
module.service( 'serviceName', function );
Resultado: ao declarar serviceName como um argumento injetável, você receberá a instância de uma função passada para
module.service
.Uso: Pode ser útil para compartilhar funções utilitárias que são úteis para chamar, simplesmente anexando
( )
à referência da função injetada. Também pode ser executado cominjectedArg.call( this )
ou similar.Fábricas
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
.Uso: Pode ser útil para retornar uma função 'class' que pode ser renovada para criar instâncias.
Aqui está um exemplo usando serviços e fábrica . Leia mais sobre o AngularJS Service vs Factory .
Você também pode verificar a documentação do AngularJS e uma pergunta semelhante sobre o stackoverflow confusa sobre serviço versus fábrica .
fonte
$providers
o tempo todo.this.myFunc = function(){}
em seu serviço (evita escrever código para criar o objeto como faria com uma fábrica) )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.
2) Ao usar o Serviço , o Angular 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.
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.
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.
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'. O que colocarmos em 'serviço', poderemos usar diretamente em qualquer controlador em que passarmos '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 Angular, eu recomendo fazer um mergulho profundo nelas.
Abaixo, o setArtist aceita um artista e permite que você o defina. O getArtist retorna o artista callItunes primeiro chama 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'.
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).
No controlador acima, estamos injetando no serviço 'myFactory'. Em seguida, definimos propriedades em nosso objeto $ scope que são provenientes de 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". 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 ao lidar com a criação de um Serviço seja o fato de ele ser 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.
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.
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.
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.
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.
Agora, tendo esse conhecimento do que a palavra-chave 'new' realmente faz em JavaScript, a criação de um Serviço em Angular 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.
Agora, anexaremos todos os nossos métodos que estarão disponíveis em nosso controlador a 'this'.
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).
Como mencionei antes, quando você realmente entende o que "novo" faz, os Serviços são quase idênticos às fábricas da Angular.
fonte
A pista está no nome
Serviços e fábricas são semelhantes entre si. Ambos produzirão um objeto singleton que pode ser injetado em outros objetos e, portanto, são frequentemente usados de forma intercambiável.
Eles devem ser usados semanticamente para implementar diferentes padrões de design.
Os serviços são para implementar um padrão de serviço
Um padrão de serviço é aquele em que seu aplicativo é dividido em unidades de funcionalidade logicamente consistentes. Um exemplo pode ser um acessador de API ou um conjunto de lógica de negócios.
Isso é especialmente importante no Angular, porque os modelos Angular geralmente são apenas objetos JSON extraídos de um servidor e, portanto, precisamos de um lugar para colocar nossa lógica de negócios.
Aqui está um serviço do Github, por exemplo. Ele sabe como falar com o Github. Ele sabe sobre URLs e métodos. Podemos injetá-lo em um controlador e ele gera e retorna uma promessa.
Fábricas implementam um padrão de fábrica
As fábricas, por outro lado, pretendem implementar um padrão de fábrica. Um padrão de fábrica no qual usamos uma função de fábrica para gerar um objeto. Normalmente, podemos usar isso para construir modelos. Aqui está uma fábrica que retorna um construtor Author:
Usaríamos isso assim:
Observe que as fábricas também retornam singletons.
Fábricas podem retornar um construtor
Como uma fábrica simplesmente retorna um objeto, ela pode retornar qualquer tipo de objeto que você desejar, incluindo uma função construtora, como vemos acima.
Fábricas retornam um objeto; serviços são renováveis
Outra diferença técnica está na forma como serviços e fábricas são compostos. Uma função de serviço será atualizada para gerar o objeto. Uma função de fábrica será chamada e retornará o objeto.
Isso significa que em um serviço, acrescentamos "this" que, no contexto de um construtor, apontará para o objeto em construção.
Para ilustrar isso, aqui está o mesmo objeto simples criado usando um serviço e uma fábrica:
fonte
Author
parâmetro do injetor deve estarPerson
.Todas as respostas aqui parecem estar relacionadas a serviço e fábrica, e isso é válido, pois era sobre isso que estava sendo perguntado. Mas também é importante ter em mente que existem vários outros
provider()
, incluindo,,value()
econstant()
.A chave a lembrar é que cada um é um caso especial do outro. Cada caso especial na cadeia permite que você faça a mesma coisa com menos código. Cada um também com algumas limitações adicionais.
Para decidir quando usar qual você acabou de ver qual permite que você faça o que deseja em menos código. Aqui está uma imagem que ilustra quão semelhantes elas são:
Para obter um detalhamento passo a passo completo e uma referência rápida de quando usar cada um, visite o post do blog onde obtive esta imagem:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
fonte
app.factory ('fn', fn) vs. app.service ('fn', fn)
Construção
Com fábricas, Angular invocará a função para obter o resultado. É o resultado que é armazenado em cache e injetado.
Com os serviços, o Angular chamará a função construtora chamando new . A função construída é armazenada em cache e injetada.
Implementação
As fábricas normalmente retornam um literal de objeto porque o valor de retorno é o que é injetado nos controladores, blocos de execução, diretivas etc.
As funções de serviço normalmente não retornam nada. Em vez disso, eles executam a inicialização e expõem funções. As funções também podem fazer referência a 'this', pois foram construídas usando 'new'.
Conclusão
Quando se trata de usar fábricas ou serviços, ambos são muito semelhantes. Eles são injetados em controladores, diretivas, bloco de execução, etc., e usados no código do cliente da mesma maneira. Eles também são dois singletons - o que significa que a mesma instância é compartilhada entre todos os locais onde o serviço / fábrica é injetado.
Então, qual você prefere? Qualquer um - eles são tão parecidos que as diferenças são triviais. Se você escolher um sobre o outro, esteja ciente de como eles são construídos, para que você possa implementá-los adequadamente.
fonte
Passei algum tempo tentando descobrir a diferença.
E eu acho que a função de fábrica usa o padrão do módulo e a função de serviço usa o padrão construtor de scripts java padrão.
fonte
O padrão de fábrica é mais flexível, pois pode retornar funções e valores, além de objetos.
Não há muito sentido no padrão de serviço IMHO, pois tudo o que faz você pode facilmente fazer com uma fábrica. As exceções podem ser:
Indiscutivelmente, o padrão de serviço é uma maneira um pouco mais agradável de criar um novo objeto do ponto de vista da sintaxe, mas também é mais caro instanciar. Outros indicaram que o angular usa "novo" para criar o serviço, mas isso não é verdade - não é possível fazer isso porque todo construtor de serviço tem um número diferente de parâmetros. O que o angular realmente faz é usar o padrão de fábrica internamente para envolver sua função de construtor. Em seguida, ele faz alguns truques inteligentes para simular o operador "novo" do javascript, chamando seu construtor com um número variável de argumentos injetáveis - mas você pode deixar de fora essa etapa se usar o padrão de fábrica diretamente, aumentando muito ligeiramente a eficiência do seu código.
fonte
function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; }
function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); }
Enquanto o MyFactory e o MyService usam o protótipo, o MyFactory ainda sofre um impacto no desempenho ao construir o objeto que está sendo retornado. Nos dois exemplos, eles têm privates, mas no MyService não há relativamente nenhuma diferença de desempenho.MyFactory(someArgument)
(ex$http()
). Isso não é possível com um serviço como você estaria fazendo referência ao construtor:MyService(someArgument)
.