The playground

More information here

smidigare UX på sidan belastning med vinkel Resolvers

som utvecklare, är du alltid ute efter att optimera din kod. Detta inkluderar den hastighet med vilken du presenterar användaren med fullastad UI, som ofta är beroende av data som kommer från en databas. oundvikligen börjar du leta efter sätt att lösa data omedelbart efter navigering till en ny sida/område i din ansökan, utan att […]

som utvecklare, är du alltid ute efter att optimera din kod. Detta inkluderar den hastighet med vilken du presenterar användaren med fullastad UI, som ofta är beroende av data som kommer från en databas.

oundvikligen börjar du leta efter sätt att lösa data omedelbart efter navigering till en ny sida/område i din ansökan, utan att användaren stöter på det som kallas page JANK.

det här är när sidan rör sig upp och ner medan vissa komponenter laddas. Det kan avsevärt påverka UX till den punkt där det ser ’buggy’.

Angular ger ett intuitivt tillvägagångssätt för att hämta data innan rutten laddas; innan den navigerade rutten löser sig.

det kallas en Vinkelresolver.

en Vinkelresolver är i huvudsak en Vinkeltjänst. En injicerbar klass som du tillhandahåller en routingmodul i ruttkonfigurationen. Denna speciella typ av tjänst injiceras och körs när den innehållande rutten navigeras till.

Resolveren löser sedan data före sidladdningen, som blir tillgänglig via tjänsten ActivatedRoute. Detta ger ett enkelt och effektivt sätt att se till att din användare har data så snabbt som möjligt innan en komponent som är viktig för den ursprungliga sidbelastningen skulle behöva den.

ett annat sätt att använda en Vinkelresolver är att använda den som en metod för att fylla i SEO-metadata direkt.

med en resolver ger du en garanti för att data kommer att finnas innan sidan har laddats, vilket säkerställer att allt har vad det behöver vid initialisering.

låt oss bryta ner Vinkelupplösaren

en Vinkelupplösare är en klass som implementerar gränssnittet Resolve. Gränssnittet Resolve kräver att du implementerar en funktion i klassen som heter resolve.

Här är Lösningsgränssnittssignaturen …

export interface Resolve<T> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T {
return 'data';
}
}

som vi kan se från gränssnittssignaturen kräver det ett generiskt argument T som kommer att vara typen av våra lösta data.

lösningsfunktionen returnerar ettObservablePromise eller bara data av typenT . Därför finns det ett förslag om att detta ska hanteras asynkront, särskilt om data hämtas från databasen.

huvudsyftet med lösningsfunktionen är att den måste slutföras. Detta faktum måste komma ihåg när du hämtar data i observerbara. Det observerbara måste slutföras. Det är trots allt en resolver.

om det observerbara inte slutförs kommer data aldrig att lösa, och sidan laddas aldrig. Därför måste du definiera den punkt där du inte behöver ta några fler värden och data kan lösa, eftersom du har allt du behöver från databasen. När du använder asynkrona dataströmmar som observerbara är detta ett användningsfall för rörbara operatörer från RXJS.

de rörbara operatörerna som kommer att tänka på när man tänker på att slutföra en dataström baserad på ett tillstånd är en kombination av filtertakefirst . Med den här kombinationen kan du filtrera alla värden som du inte vill ta, till exempel null eller undefined eller en tom array , sedan take det första giltiga värdet med take(1).

operatörer som kan behövas för att slutföra ett observerbart tidigt när du stöter på problem eller fel, där du vill returnera null eller omdirigera, är catchError och timeout . En kombination av timeout och catchError är användbar om dina data tar för lång tid och du vill returnera null så att du kan försöka igen inuti komponenten, eller om du vill omdirigera.

om dina data inte löser sig snabbt, baseras på komplex filtrering, logik, stora mängder databasanrop, kommer du sannolikt att uppleva problem då och då.

det är bäst att bestämma minsta mängd databasanrop och minsta data som behövs för att framgångsrikt och graciöst ladda sidan.

följaktligen kan du dra nytta av att spendera lite tid innan du implementerar din resolver för att fokusera på att separera innehållet ovanför vikningen från data som kan laddas när sidan initieras.

därför kan du dela upp de data som behövs för en smidig UX, från resten av data som kan anropas från komponenten, snarare än resolveren.

Du kan då uteslutande hantera det minimala, ovanför vikningen, innehållet genom upplösaren.

denna dynamiska metod för sidladdning kan hjälpas med användning av skelett. Så att om användaren rullar ner direkt kan du ge användaren indikationen att innehållet laddas och därefter förbättra UX.

Steg 1: Skapa Resolver

Vi måste skapa vinkel Resolver. Det finns dock inte ett Angular CLI-kommando som genererar en resolver. Därför måste vi själva skriva dekoratören (resolver-metadata).

lyckligtvis är det bara några rader kod som bildar pannplattan för en resolver, och vi kan ta den injicerbara dekoratören från en befintlig tjänst om du kämpar för att komma ihåg det.

kommentera Profilresolverklassen med en injicerbar dekoratör

först tillhandahåller vi den injicerbara dekoratören med providedIn: any I konfigurationen.

@Injectable({ providedIn: 'any'})

Vi kommer då att namnge vår resolver genom att lägga till konventionen Resolver . I det här exemplet kommer vi att lösa profildata (användardata), så vi kommer att kalla det ProfileResolver .

eftersom det är en resolver, och Angular känner igen funktionen för resolvers, kan vi implementera Resolve – klassen, som kommer att ge signaturen som vi måste implementera i vår resolve-funktion för att framgångsrikt lösa data.

@Injectable({providedIn: 'any'})
export class ProfileResolver implements Resolve<Profile> {
}

vår lösningsfunktion returnerar en observerbar med data som överensstämmer med gränssnittet Profile. Därför kommer vi att tillhandahålla gränssnittet Profile som det generiska argumentet till resolver-klassen och funktionen resolve(). På så sätt har vi anpassat oss till Vinkelkrav för en resolver.

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T {
return;
}

lös implementeringen ger oss två parametrar om de behövs,route ochstate . Dessa fylls automatiskt och är tillgängliga från vår resolve() funktion.

Därefter måste vi faktiskt lösa verkliga data från databasen, vilket kommer att bli vårt nästa steg.

hämta data från databasen

för att hämta data för vår lösningsfunktion måste vi injicera tjänsten som tillhandahåller data; en som interagerar med databasen.

Vi tar vad vi behöver från det för att lösa snabbt så att användaren navigerar snabbt och framgångsrikt. För denna demo kommer vi inte att oroa oss för den underliggande tjänsten som handlar om databasen. Vi kommer bara att injicera tjänsten med hjälp av beroendeinjektion i konstruktörsargumentet för vår ProfileResolver klass.

eftersom våra data kommer i form av en observerbar dataström med flera värden som avger asynkront, behöver vi bara take(1) med den rörbara operatören take importerad från rxjs/operator . Annars skulle den observerbara aldrig slutföra, och resolver skulle aldrig…lösa.

vi behöver bara ett utsläpp / värde och take kompletterar det observerbara för oss.

det är så enkelt som att skapa en resolver; vi behöver bara returnera det observerbara i funktionen resolve() som angular hanterar prenumerationen på.

Profileresolver-klassen

vi hanterar eventuella fel vid hämtning av data genom att omdirigera till en överordnad rutt.

Bonus: Fyll i dynamiska SEO-metadata snabbt innan rutten har laddats

fördelarna med att fylla i våra <meta> – taggar har omedelbart uppenbara fördelar. Ju snabbare vår SEO-metadata fylls i, desto snabbare återspeglar vår SEO korrekt och korrekt sidinnehållet.

det betyder att det är enklare och snabbare för robotar, som de som drivs av sökmotorer som Google och Bing, att genomsöka din webbplats och hämta innehållet.

detta är inte så viktigt på förrenderade sidor eller de som återges av Angular Universal, eftersom all rendering är klar innan robotarna tar emot innehållet.

men om du litar på den (ofta tvivelaktiga) förmågan för google-robotar att tolka javascript för din SEO, eller om du har en on-demand-lösning som puppeteer som behöver försäkran om att SEO kommer att vara korrekt innan du returnerar den renderade DOM, bör en resolver som innehåller SEO hjälpa. Så det hjälper när sökroboten är tidsbegränsad.

det skiljer också problem från komponenten, så att komponenten inte behöver hantera något SEO-relaterat. En av de främsta anledningarna till att jag gillar resolvers.

steg 2: injicera resolver i routing module

ProfileRoutingModule där vi kommer att ge vår resolver är en lat laddad modul. Därför kommer vår rotväg att vara tom med parametertoken userSlug , som vi måste hämta rätt profildata.

för att tillhandahålla vår resolver, tillhandahåller vi bara ett objekt med namnet på våra data som nyckel och den specifika resolver som det värde som kommer att ansvara för att lösa dessa data.

Du kan namnge nyckeln vad du vill, men vi kallar det bara data.

vår ProfileRoutingModule

det är allt som krävs i routingmodulen för att vi ska kunna använda vår resolver.

Därefter måste vi hämta och använda våra data i komponenten.

steg 3: Initiera komponenten med lösta data

Nu när vi har löst våra data om ruttaktivering är data tillgängliga via Tjänsten ActivatedRoute. Eftersom vi har att göra med observerbara, kommer vi genom hela applikationen att skapa en ström som binder till egenskapen data som kommer att vara våra lösta data.

först injicerar vi ActivatedRoute I konstruktören av vårt ProfileComponent . Därefter tilldelar vithis.route.data tillprofile$ observerbar. Vi vill också byta till att använda en observerbar när uppdaterade data kommer från databasen så att vi har nya data när vi interagerar med appen.

För detta kommer vi att använda startWith så att vi börjar vår ström med det värde som är lättillgängligt från this.route.snapshot.data. Vi kommer sedan åt egenskapen data som this.route.snapshot.datastartWith anger ett värde att börja med, som det första utsläppet av vår ström.

vår Profilkomponent

vad omedelbart tillgängliga data gör för komponenten

omedelbart tillgängliga data minskar tiden för att ladda de enskilda delarna av den sidan, vilket observeras av användaren. Resultatet av att inte använda en resolver så här är att sidan kan tyckas ladda på ett fragmenterat sätt, vilket inte är visuellt tilltalande.

därför måste du vara uppmärksam på vilka delar av dina HTML-mallar som är beroende av vilken data. Du bör sedan skriva din resolver för att stödja dessa element och den totala effekten på sidan laddar UX.

det finns flera sätt att komponenten kan ladda fragmenterad

  • en av dessa är om du har ett ngIf I flera delar av din HTML-mall.
  • en annan är ngFor .

det är bästa praxis att begränsa mängden enskilda ngIf du skriver i syfte att begränsa mängden storleksändring webbläsaren har att göra.

Om du laddar sidan innan du hämtar data kan delar av din sida hoppa, lagga och ändra storlek hela tiden, vilket får UX att lida.

att implementera en resolver kan vara skillnaden mellan användaren som upplever 3-5 sekunder hoppning och storleksändring jämfört med 0,5 sekunder, vilket ofta är för snabbt för att skada den totala UX.

det är det! Vi har en resolver med en förbättrad UX på sidan belastning.

Lämna ett svar

Din e-postadress kommer inte publiceras.