Aprenda como implementar serviços em Angular com nosso tutorial abrangente. Melhore o desempenho e a funcionalidade do seu aplicativo com nosso guia passo a passo.
Angular é uma estrutura amplamente utilizada para construir aplicações web complexas e escaláveis com foco no desempenho e na experiência do usuário. De acordo com Pesquisa de desenvolvedor Stack Overflow 2022é o quinto framework web mais popular entre desenvolvedores profissionais em todo o mundo, depois do React.
Um dos principais recursos do Angular são seus serviços. Os serviços são cruciais para a construção de aplicações modulares e escaláveis. Eles ajudam a organizar o código, separar preocupações e aumentar a modularidade. Isso facilita o gerenciamento e a manutenção de grandes bases de código. Serviços em Angular são objetos singleton que podem ser injetados em qualquer componente, diretiva ou serviço. Isso os torna uma ferramenta poderosa para construir aplicativos complexos.
Aqui, iremos nos aprofundar no mundo dos serviços em Angular e abordar técnicas avançadas e melhores práticas relacionadas à sua implementação. Ele explorará como os serviços podem executar tarefas como recuperação de dados, armazenamento em cache e registro. Ao final deste artigo, você terá um conhecimento sólido dos serviços Angular e estará pronto para usá-los para construir aplicativos da web robustos e escalonáveis.
Vamos começar!
Noções básicas sobre serviços em Angular
Os serviços angulares são usados para encapsular lógica que pode ser compartilhada entre diferentes componentes ou módulos. Eles são uma parte fundamental na construção de aplicativos com o framework.
Injeção de Dependência é um padrão de design usado em Angular para fornecer instâncias de objetos para componentes que dependem deles. O uso de uma abstração chamada Injector Angular facilita a comunicação entre consumidores e provedores de dependência. O injetor verifica seu registro em busca da dependência fornecida para verificar se já possui uma instância. Um novo é feito e adicionado ao cadastro caso não exista. Os serviços geralmente são fornecidos na raiz da aplicação e qualquer componente que precise utilizá-los pode simplesmente declará-los como um parâmetro do construtor.
Os casos de uso comuns para serviços Angular incluem fazer solicitações HTTP, gerenciar estado, trabalhar com APIs de terceiros e lidar com eventos ou lógica em todo o aplicativo.
Classe de componente e classe de serviço: o básico
A classe de componente e a classe de serviço em um aplicativo Angular são blocos de construção fundamentais.
A classe de componente é usada para gerenciar a interface do usuário e as interações. A estrutura e o comportamento que eles definem para uma parte específica da interface do usuário estão vinculados ao modelo onde a interface do usuário é definida.
A classe de serviço, por outro lado, contém lógica de negócios, gerenciamento de estado e acesso a dados. Ele fornece uma maneira de compartilhar funcionalidades e tarefas entre componentes. Tais tarefas de processamento no nível de serviços em Angular tornam a lógica do aplicativo mais modular.
Os componentes dependem de serviços em Angular para executar tarefas como busca de dados ou gerenciamento de estado, enquanto os serviços são códigos reutilizáveis que não dependem dos componentes.
Angular usa um recurso chamado injeção de dependência para facilitar a conexão entre os dois. O recurso permite que os desenvolvedores injetem uma classe de serviço em uma classe de componente, facilitando o compartilhamento de dados com o componente.
A injeção de dependência funciona criando um injetor central que gerencia a instanciação e a vida útil dos serviços em Angular. Sempre que um serviço é necessário, o componente declara uma dependência em seu construtor. A injeção de dependência Angular garante que cada componente tenha sua própria instância de serviço. A estrutura distingue componentes de serviços para aumentar a modularidade.
A manutenção do aplicativo se torna mais fácil ao dividir as preocupações de gerenciamento da interface do usuário e da lógica de negócios em um componente ou classe de serviço separada. A separação de interesses é uma ideia importante em Angular porque diz que o código no módulo e nas camadas de um aplicativo deve se concentrar em uma única tarefa por vez e não lidar com outras coisas dentro do mesmo módulo ou camada.
Essa separação de preocupações entre provedores de componentes e serviços permite que os desenvolvedores se concentrem em recursos ou visualizações específicas sem precisar se preocupar com a lógica de negócios subjacente ou com o acesso aos dados.
Criando um serviço angular
Esta seção do artigo se concentrará em como criar um serviço em Angular.
Pré-requisitos
Para implementar um serviço em Angular com sucesso, você deve ter o seguinte:
- Node.js: A última versão do Node.js na sua máquina
- Um editor de código: Qualquer IDE que suporte Angular
- npm: Node Package Manager para instalar as dependências necessárias
- CLI angular: A versão mais recente que fornece núcleo Angular
Instale as dependências necessárias
Se você não tiver o Angular pré-instalado em sua máquina. Use o seguinte comando no terminal para instalar o Angular CLI.
npm install -g @angular/cli
Crie um novo projeto
Para criar um novo projeto angular e um aplicativo inicial, execute o comando CLI ng new e forneça o nome my-app.
ng new my-app
Seu arquivo package.json deve ser parecido com isto.
Crie um serviço
Para criar um serviço no aplicativo Angular, o comando a seguir é usado por meio da CLI.
ng generate service <service name>
Para este aplicativo, execute o seguinte comando no terminal.
ng generate service ../shared/user
O comando acima informa ao Angular CLI para criar um novo serviço chamado user no diretório compartilhado do aplicativo Angular. Dois novos arquivos aparecerão assim que o comando for executado. Um arquivo de teste de unidade é criado, que pode ser encontrado no arquivo user.service.spec.ts. Embora os testes unitários não sejam abordados aqui, é importante saber que eles existem. user.service.ts é o outro arquivo e o próprio serviço incluirá a lógica.
Configurando o serviço
Ao navegar até o arquivo user.service.ts você notará que a classe de serviço possui um decorador.
@Injectable({ providedIn: 'root' }).
Este decorador instrui o Angular a registrar o serviço customizado no nível raiz da aplicação, permitindo assim que o serviço seja utilizado por meio de injeção de dependência em qualquer um dos componentes da aplicação.
Se um serviço não for usado e estiver no aplicativo. O @Injectable permite que o serviço Angular otimize o aplicativo removendo o serviço.
A propriedade fornecidoIn é usada para especificar o injetor para um serviço usando o sistema de injeção de dependência do Angular.
A propriedade provideIn possui três valores possíveis:
Fornecido em | Função |
---|---|
raiz | Este é o valor padrão e significa que o serviço será fornecido no injetor raiz. O injetor raiz é compartilhado por todos os módulos e componentes do aplicativo e é o injetor de nível superior. |
plataforma | Esta opção disponibiliza o serviço em todos os aplicativos em execução no nível da plataforma, em vez de em todos os componentes do mesmo módulo. |
qualquer | Esta opção fornece um serviço no nível do módulo. O serviço está disponível para todos os componentes do mesmo módulo. |
Para este tutorial, estamos usando o valor raiz da propriedade provideIn.
Para os fins deste tutorial, estamos codificando dados falsos no serviço. Observe que em um cenário real, os dados são obtidos de outros serviços por meio de uma API antes de serem enviados desta forma. Um Observable precisa ser retornado para que um usuário possa assinar. Portanto, Observerable e of devem ser importados da biblioteca RxJs.
Navegue até a pasta do aplicativo src, abra o arquivo user.service.ts e adicione o código a seguir.
import { Observable, of } from 'rxjs';
Agora implemente uma função simples, que retorna uma lista de dados do usuário. Adicione a seguinte função na classe de serviço injetável.
getUser : Observable<any>{ let userAray = ( { username: 'johndoe', firstName: 'John', lastName: 'doe', age: 34 }, { username: 'simondoe', firstName: 'Simon', lastName: 'doe', age: 28 }, { username: 'timdoe', firstName: 'Tim', lastName: 'doe', age: 38 }, ); return of(userAray); }
A instrução return usa um of Observável que envia o número de valores na sequência e, em seguida, envia uma notificação na conclusão. No nosso caso, ele envia uma série de dados simulados do usuário.
Injetando serviço angular na classe de componente
Agora, vamos adicionar o serviço criado anteriormente ao componente do aplicativo usando seus métodos. UserService está disponível para nós no nível raiz por meio do sistema de injeção de dependência Angular.
Abra o arquivo app.component.ts primeiro e importe o seguinte:
constructor( private userService: UserService) { }
Agora, adicione um construtor à classe do componente App.
constructor( private userService: UserService) { }
Ao adicionar o construtor do componente acima, sempre que a classe do componente do aplicativo for instanciada, o UserService será injetado para que o serviço possa ser usado adequadamente.
Em seguida, crie um nome de função getUser que será chamado para renderizar os dados no gancho do ciclo de vida ngOnInit. A função não retornará dados. O comando gera dados se estiver inscrito em um Observable.
userArray: any; getUser { this.userService.getUser .subscribe( user => { this.userArray = user }); } ngOnInit { this.getUser }
Seu arquivo app.component.ts deve ser parecido com isto.
A seguir, para exibir dados na página da web, abra o arquivo app.component.html e adicione o código a seguir.
{{ userArray json }}
The above code displays the data in the HTML file in json format.
Ao executar o aplicativo no navegador, você pode ver a saída buscando dados do serviço.
O padrão Singleton em serviços angulares
O Padrão Singelton é um padrão de design que restringe a instanciação de uma classe a uma única instância e fornece um ponto global de acesso a essa mesma instância. É frequentemente usado em situações em que ter múltiplas instâncias do mesmo tipo de classe pode causar problemas.
Angular segue o padrão Singleton por padrão. Isso significa que sempre que um serviço é injetado em um novo componente ou outro serviço, a mesma instância desse serviço é usada em toda a aplicação.
O uso do Padrão Singleton simplifica a arquitetura do aplicativo e reduz as chances de bugs. Também leva a uma única fonte de dados de serviço em todo o aplicativo.
Comunicação entre componentes usando serviços
Assim que o aplicativo se torna complexo, muitas vezes é necessário que vários componentes do aplicativo se comuniquem entre si. Existem várias maneiras de se comunicar dentro do aplicativo com diferentes componentes.
O Angular fornece vários mecanismos prontos para fazer isso, mas eles podem se tornar complicados e difíceis de gerenciar em um aplicativo grande com muitos componentes interconectados. É aqui que entram os serviços.
Os serviços são usados para facilitar a comunicação, agindo como um sistema de comunicação centralizado. Os componentes usam os serviços para enviar mensagens ou dados para outros componentes e depois recebê-los também.
Um padrão comum usado para implementar comunicação usando serviços em angular é o uso de Assuntos e Observáveis. Um assunto é um tipo de Observável que permite que os valores sejam enviados para ele, em vez de apenas poder assinar os valores. Vejamos um exemplo de como isso pode parecer.
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class DataService { private dataSubject = new Subject<string> ; sendData(data: string) { this.dataSubject.next(data); } getData { return this.dataSubject.asObservable ; } }
Neste exemplo, o DataService expõe um dataSubject privado. O serviço possui um método sendData que pega uma string e a envia para o dataSubject usando o próximo método. O serviço também possui um método getData que retorna o dataSubject como um Observable, que pode ser assinado pelo componente filho.
Para utilizar este serviço em múltiplos componentes, você pode injetar o DataService e utilizar seus métodos para enviar e receber dados de diferentes provedores. Por exemplo, no componente pai, você pode fazer o seguinte.
import { Component } from '@angular/core'; import { DataService } from './data.service'; @Component({ selector: 'app-parent', template: ` <button (click)="sendData ">Send Data</button> ` }) export class ParentComponent { constructor(private dataService: DataService) {} sendData { this.dataService.sendData('Hello from the parent component!'); } }
Neste exemplo, o ParentComponent injeta o DataService e possui um botão que chama o método sendData para enviar uma mensagem ao componente filho.
No arquivo do componente filho, adicione o seguinte código.
import { Component } from '@angular/core'; import { DataService } from './data.service'; @Component({ selector: 'app-child', template: ` <p>{{ data }}</p> ` }) export class ChildComponent { data: string; constructor(private dataService: DataService) { this.dataService.getData .subscribe(data => { this.data = data; }); } }
No código acima, o ChildComponent injeta o DataService e assina seu método getData para receber dados do componente pai. Quando os dados são recebidos e apresentados de volta, o componente atualiza seu modelo para exibir os dados recebidos.
Ao implementar a abordagem mostrada acima você pode facilmente passar dados entre os componentes utilizando o serviço tornando a comunicação mais eficiente.
Otimizando Serviços Angulares para Desempenho
Como desenvolvedor Angular, otimizar o desempenho do serviço é crucial para criar aplicações em larga escala com excelente experiência do usuário. Aqui estão algumas práticas recomendadas para otimizar o desempenho dos serviços Angular.
- Memoização: Este é o processo de armazenar em cache o resultado de uma chamada de função para que chamadas subsequentes com os mesmos parâmetros de entrada possam ser retornadas do cache em vez de recalcular a função. Pode reduzir significativamente o tempo de computação, especialmente ao lidar com operações complexas que envolvem muita manipulação de dados.
- Minimizando solicitações de rede: Você pode usar técnicas como lote, cache e carregamento lento para minimizar as solicitações de rede.
- Implementando carregamento lento: Isso pode ajudar a reduzir o tempo de carregamento inicial de um aplicativo. Ele carrega os serviços apenas quando eles são necessários.
- Aproveitando operadores RxJS: Operadores como switchMap e mergeMap podem ajudar a reduzir o número de solicitações HTTP. Eles combinam várias solicitações em uma única solicitação.
Mecanismos robustos de tratamento de erros e novas tentativas em serviços angulares
O tratamento de erros e os mecanismos de nova tentativa são essenciais para a criação de um serviço Angular tolerante a falhas. Aqui estão algumas técnicas para lidar com erros e implementar mecanismos de nova tentativa:
- Tratamento de erros RxJS: A maioria dos operadores em RxJs são catchError e retry. catchError é usado para tratar erros retornando um valor substituto ou lançando um novo erro. retry é usado para repetir automaticamente uma operação um determinado número de vezes em caso de erros.
- Implementando mecanismos de nova tentativa: Eles melhoram a experiência do usuário de um aplicativo, repetindo automaticamente solicitações com falha. Você pode implementar um mecanismo de nova tentativa usando operadores RxJS como nova tentativa e atraso. Por exemplo, o código a seguir tenta novamente uma solicitação HTTP até três vezes com um atraso de um segundo entre cada nova tentativa.
import { of } from 'rxjs'; import { catchError, delay, retry } from 'rxjs/operators'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class DataService { private dataUrl=" constructor(private http: HttpClient) { } getData { return this.http.get<Data>(this.dataUrl).pipe( retry(3), catchError(error => { console.error('Error fetching data:', error); return of(null); }), delay(1000) ); } }
No código acima, o método getData tenta novamente a solicitação HTTP até três vezes usando o operador retry. Se a solicitação ainda falhar após três tentativas, o operador catchError registra o erro e retorna nulo. O operador de atraso adiciona um atraso de um segundo entre cada nova tentativa.
Testando serviços angulares
Os testes garantem que o aplicativo funcione conforme planejado e forneçam um alto nível de confiança de que ele atende aos requisitos e especificações. Também ajuda a identificar bugs e erros rapidamente. Isso reduz o tempo e o custo que podem surgir posteriormente devido aos problemas se não forem identificados antecipadamente.
Configurando testes unitários para um serviço Angular
- Crie um novo arquivo com a extensão .spec.ts no mesmo diretório do arquivo de serviço que está sendo testado.
- Importe as dependências necessárias, incluindo o serviço que está sendo testado.
- Escreva um ou mais casos de teste usando a estrutura de testes Jasmine. Cada caso de teste deve instanciar o serviço e chamar um de seus métodos, testando o valor de retorno em relação ao resultado esperado, validando assim a entrada do usuário e zombando dela.
- Use as funções de teste do Jasmine, como expect e toEqual , para verificar os resultados dos casos de teste.
Conclusão
Dominar conceitos e técnicas de serviços Angular é crucial para que os desenvolvedores criem aplicativos Angular modulares e de fácil manutenção. Com a ajuda de conceitos avançados como injeção de dependência, padrão singleton e técnicas de tratamento de erros, os desenvolvedores podem criar serviços robustos e tolerantes a falhas.
A terceirização pode oferecer diversas vantagens, incluindo acesso a desenvolvedores talentosos com experiência em Angular e outras estruturas. Isso pode economizar tempo e recursos, permitindo que você se concentre em outros aspectos cruciais do seu negócio. Além disso, também garante uma entrega eficiente e econômica. Você pode contratar uma empresa especializada em fornecer serviços de desenvolvimento Angular de alto nível.
Explore suas opções e avalie os prós e os contras de diferentes estruturas, pois cada projeto é diferente. É vital encontrar a melhor opção para o seu projeto e impulsionar o seu negócio a novos patamares. Ao explorar várias opções e comparar o Angular com outras estruturas populares como React ou Vue, você poderá tomar uma decisão informada e encontrar a opção perfeita para o seu projeto.