Vinkletjenester og afhængighedsinjektion forklaret

Services og injektorer

Komponenter er ansvarlige for de data, der gengives i skabelonen. At have eksterne tjenester at trække på kan forenkle dette ansvar. Desuden er indkapsling af fremmed meget lettere at vedligeholde.

Delegering af for mange ansvarsområder på en enkelt komponent kan komplicere komponentklassen. Og hvad hvis disse ansvarsområder gjaldt flere komponenter? Kopiering og indsættelse af sådan logik er ekstremt dårlig praksis. Enhver fremtidig ændring af logikken ville være sværere at implementere og teste.

Vinklet betød at bremse dette problem med tjenester og afhængighedsindsprøjtning. Begge koncepter arbejder sammen for at give modulær funktionalitet.

Komponenter behøver heller ikke at give nogen fremmed information. En service importerer, hvad den har brug for til at fungere på vegne af de komponenter, den servicerer . Komponenterne behøver kun at instantiere tjenesten. Derfra betjener de deres egne behov med den instantierede serviceinstans.

Hvad angår test og fremtidig modifikation, er al logik ét sted. Tjenesten øjeblikkelig fra dens kilde. Test og ændringer af kilden gælder overalt, hvor tjenesten injiceres.

Introduktion til tjenester

En tjeneste er en type skematisk tilgængelig i Angular. Det er kan genereres af kommandoen-line interface (CLI): ng generate service [name-of-service]. Erstat [name-of-service]med et foretrukket navn. CLI-kommandoen giver følgende.

import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class LoggerService { constructor() { } }

Logikken i en tjeneste er forskellig inden for dens klasse. Angular fortolker en klasse som en injicerbar service baseret på @Injectabledekoratøren. Injicerbare tjenester skal registreres hos en injektor.

Komponenten instantierer en tjeneste, mens injektoren leverer den instans. Fortsæt med at læse ind i det næste afsnit for at få mere at vide om injektorer.

Den @Injectablemetadatafelt providedIn: ‘root’målretter roden modul af det aktuelle program ( app.module.ts). Det registrerer tjenesten med modulets injektor, så den kan indsprøjte denne service i nogen af ​​sine børn.

Injektorer er byggestenene i Angular's afhængighedsindsprøjtningssystem. Injektorer er et godt sted at fokusere din opmærksomhed på, inden du fortsætter med tjenester.

Injektorer

En applikation, der begynder med app.module.ts, indeholder et hierarki af injektorer. De findes ved siden af ​​hvert modul og komponent i applikationstræet.

Applikationshierarki

De grønne cirkler angiver injektorer. De leverer serviceinstanser til instantierende komponenter. Afhængigt af hvilken injektor en tjeneste er registreret hos, er den muligvis ikke tilgængelig for en komponent.

Tjenester, der er registreret ved roden af ​​appen ( app.module.ts), er tilgængelige for alle komponenter. En injektor til en komponent har muligvis ikke en bestemt tjeneste registreret. Hvis det er tilfældet, og komponenten anmoder om en instantiering, vil injektoren henvise til sin forælder. Denne tendens fortsætter, indtil enten at nå rodinjektoren eller servicen findes.

Når du ser på diagrammet, skal du sige, at en tjeneste registreres ved punkt B's injektor. Alle komponenter på punkt C og ned kan ikke få adgang til den service, der er registreret på B's injektor. Injektorer udsætter aldrig deres børn for en serviceinstans.

Afhængighedsinjektion

Der er flere måder at registrere en service på en applikations injektorer.

Den providedIn: ‘root’metadata inden for @Injectablegiver den mest anbefalede metode. Dette metadatafelt udgivet med Angular 6.

Som nævnt før providedIn: ‘root’registrerer en tjeneste med rodmodulinjektoren. Det kan instantieres på tværs af hele applikationen som et resultat.

Nyheden ved providedIn: ‘root’er trærystning . Hvis tjenesten er ubrugt på trods af sin registrering, rystes den fra applikationen i løbetid. På den måde bruger det ikke nogen ressourcer.

De to andre måder er mere direkte og traditionelle. Indrømmet, de tilbyder ikke trærystning.

En tjeneste kan registreres med en hvilken som helst injektor langs komponenttræet. Du indsætter tjenesten som en udbyder i @Componentmetadatafelt: providers: []. Tjenesten er tilgængelig for komponenten og dens børn

I den tredje registreringsstrategi providers: []eksisterer metadataene som sit eget felt i @NgModuledekoratøren. Tjenesten kan instantieres fra modulet til det underliggende komponenttræ.

Husk, at i modsætning til med providedIn: ‘root’, tilbyder @NgModuleregistrering ikke trærystning. Begge strategier er ellers identiske. Når en tjeneste registreres hos @NgModule, bruger den ressourcer, selvom den ikke bruges af applikationen.

Tjenester fortsat

At skrive en faktisk tjeneste kommer derefter. For at resumere håndterer tjenester visse funktioner på vegne af programmets komponenter.

Tjenester udmærker sig ved håndtering af almindelige operationer. De sparer komponenter for ansvaret ved at gøre det. Det sparer tid uden at skulle omskrive almindelige operationer på tværs af flere komponenter. Det kan også testes mere, fordi koden er ét sted. Ændringer skal kun ske ét sted uden at skulle søge andre steder.

Brug sager

Et par eksempler går langt mod en fuldstændig forståelse af tjenester.

  • konsollogfiler
  • API-anmodninger

Begge er almindelige på tværs af de fleste applikationer. At have tjenester til at håndtere disse operationer vil reducere komponentens kompleksitet.

Konsollogfiler

Dette eksempel bygger op fra @Injectablebasisskelettet. Skelettet er tilgængeligt ved at udføre CLI ( ng generate service [name-of-service]]).

// services/logger.service.ts import { Injectable } from '@angular/core'; interface LogMessage { message:string; timestamp:Date; } @Injectable({ providedIn: 'root' }) export class LoggerService { callStack:LogMessage[] = []; constructor() { } addLog(message:string):void { // prepend new log to bottom of stack this.callStack = [{ message, timestamp: new Date() }].concat(this.callStack); } clear():void { // clear stack this.callStack = []; } printHead():void  printLog():void { // print bottom to top of stack on screen this.callStack.reverse().forEach((logMessage) => console.log(logMessage)); } getLog():LogMessage[] { // return the entire log as an array return this.callStack.reverse(); } }

LoggerService registrerer sig med rodmodulet gennem @Injectablemetadataene. Således kan det instantieres i app.component.html.

// app.component.ts import { Component, OnInit } from '@angular/core'; import { LoggerService } from './services/logger.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { logs:object[] = []; constructor(private logger:LoggerService) { } updateLog():void { this.logger.printHead(); this.logs = this.logger.getLog(); } logMessage(event:any, message:string):void { event.preventDefault(); this.logger.addLog(`Message: ${message}`); this.updateLog(); } clearLog():void { this.logger.clear(); this.logs = []; } ngOnInit():void { this.logger.addLog(“View Initialized”); this.updateLog(); } }

Skabelonen HTML giver yderligere indsigt i komponentens brug af LoggerService.

Log Example

SUBMIT

Complete Log

CLEAR
  • {{ logs.length - i }} > {{ log.message }} @ {{ log.timestamp }}

Dette har følelsen af ​​en ToDo-applikation. Du kan logge beskeder og rydde loggen over beskeder. Forestil dig, hvis al logikken fra tjenesten blev skubbet ind i AppComponent! Det ville have kompliceret koden. LoggerService holder den logrelaterede kode indkapslet fra AppComponent-klassen.

Hent anmodninger

Here is one more example worth playing around with. This example is possible thanks to typicode’s JSONPlaceholder1. The API is public and free to use.

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; // //jsonplaceholder.typicode.com // public API created by typicode @ //github.com/typicode interface Post { userId:number; id:number; title:string; body:string; } @Injectable({ providedIn: 'root' }) export class PlaceholderService { constructor(private http:HttpClient) { } getPosts():Observable { return this.http.get('//jsonplaceholder.typicode.com/posts'); } getPost(id:number):Observable { return this.http.get(`//jsonplaceholder.typicode.com/posts/${id}`); } }

This is more of a stand-alone piece than a fully fleshed out example. Fetch requests tend to work better as an injectable service. The alternative is an over-complicated component. The injected class subscribes to what the PlaceholderService pre-configures.

Conclusion

Services and dependency injection are very useful together. They allow developers to encapsulate common logic and inject across multiple different components. This alone is a massive convenience for any future maintenance.

Injectors work as intermediaries. They mediate between instantiating components and a reservoir of registered services. Injectors offer these instantiable services to their branch children.

Se de næste par links for mere information om tjenester og indsprøjtning af afhængighed.

Ressourcer til Angular

  • Vinklet dokumentation
  • I introduktionen til vinkelafhængighedsinjektion
  • Hvad er afhængighedsinjektion, og hvornår skal du bruge det
  • Bedste eksempler på kantet kode
  • Vinklet GitHub-lager
  • Afhængighedsinjektion
  • Introduktion til tjenester og DI