Preloading Strategy de rotas no Angular.
Preloading Strategy no Angular, uma possível solução para seus problemas!
Atualmente o tempo de carregamento de um site, aplicativo ou sistema faz muita diferença para satisfazer o usuário final e evitar até mesmo perdas financeiras. É cada vez mais importante otimizar o tempo de carregamento do aplicativo, pois isso estabelecerá uma primeira impressão positiva. Vamos aprender mais sobre isso neste artigo!
O que é PreloadingStrategy?
Os aplicativos construídos em Angular são modulares e nos permitem construir o frontend em blocos de módulos, que são pequenos contextos que podemos optar por isolar ou compartilhar com outros módulos. Podemos carregar esses módulos lentamente (por demanda) quando o usuário navega para uma rota. Precisamos marcar os módulos para serem carregados lentamente usando a propriedade loadChildren
do roteador.
Ao carregar os módulos utilizando Lazy loading, podemos reduzir o tamanho inicial do download do aplicativo e, assim, fazer com que o aplicativo carregue apenas as rotas que o usuário está realmente utilizando.
Isso é muito útil no caso de grandes aplicativos. Mas quando o usuário navega para uma parte de carregamento lento do aplicativo, ou seja que não foi baixada, o angular terá que baixar o módulo do servidor, o que significa que o usuário terá que esperar o download terminar.
Mas ao utilizar o PreloadingStrategy o módulo que está em lazy loading
, o usuário não precisa esperar que o módulo seja baixado, pois o módulo já foi baixado em segundo plano.
Ativando o Preloading
Para fazer uso do Pré-carregamento, primeiro precisamos habilitar o carregamento lento dos Módulos. Marque os módulos com o loadChildren
, quando você definir rotas como mostrado abaixo. O angular carregará lentamente esses módulos.
const routes: Routes = [
path: 'conta',
loadChildren: () => import('./conta/conta.module')
.then(m => m.ContaModule)
];
Agora sim podemos habilitar o pré-carregamento utilizando o preloadingStrategy: PreloadAllModules, enquanto registra as rotas usando o forRoot
método.
RouterModule.forRoot(routes, {preloadingStrategy: PreloadAllModules})
Personalizando a estratégia!
Com PreloadAllModules
todos os módulos são pré-carregados, o que pode realmente criar um gargalo caso a aplicação tenha um grande número de módulos a serem carregados. Por isso é importante entender o contexto que a aplicação se encontra e como isso pode afetar o desempenho do site ou app em dispositivos mais lentos, lembre-se que nosso objetivo principal é ter performance. Algumas estratégias para esses casos são:
- Despejando os módulos necessários na inicialização.
- Pré-carregar todos os módulos usados com frequência, chamando alguns com um delay.
- Utilizar apenas o Lazy load em módulos restantes.
Vamos ver como podemos utilizar uma estratégia customizada para Preloading de modules.
Implementando o PreloadingStrategy!
No mundo real, com aplicações que demandam performance, você pode definir um atraso antes de pré-carregar o módulo. Você também pode definir atrasos diferentes para rotas diferentes.
Veja as duas rotas a seguir. Adicionamos dados à rota. As duas rotas têm atrasos diferentes:
const routes: Routes = [
{ path: "test", loadChildren: () => import('./teste/teste.module').then(m => m.TestModule), data: { preload: true, delay: 5000 } },
{ path: "conta", loadChildren: () => import('./conta/conta.module').then(m => m.ContaModule), data: { preload: true, delay: 7000 } },
];
Agora vamos ver como implementar e customizar o PreloadingStrategy. Dê uma olhada na classe abaixo:
import { Injectable } from '@angular/core';
import { Observable, of, timer } from 'rxjs';
import { map } from 'rxjs/operators'
import { PreloadingStrategy, Route } from '@angular/router';
@Injectable()
export class CustomPreloadingStrategy implements PreloadingStrategy {
preload(route: Route, loadMe: () => Observable<any>): Observable<any> {
if (route.data && route.data['preload']) {
var delay: number = route.data['delay']
console.log('pre carregamento acionado na rota ' + route.path + ' com um delay de ' + delay);
return timer(delay).pipe(
map(_ => {
console.log("Carregando " + route.path + ' modulo');
return loadMe();
}));
} else {
console.log('Nenhum pré carregamento ' + route.path);
return of(null);
}
}
}
Como pode ver, implementamos a classe PreloadingStrategy
, em seguida, verificamos os dados da rota. Se a pré-carga for verdadeira, verificamos o atraso. E se não for definido route.data
ou preload for falso, retornamos o observável de null of(null).
Outra etapa essencial é que precisamos fornecê-lo como provider
no AppModule, conforme mostrado abaixo no código:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CustomPreloadingStrategy } from './custom-preloading-strategy/custom-preloading-strategy.services';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
],
providers: [CustomPreloadingStrategy],
bootstrap: [AppComponent]
})
export class AppModule { }
Qual o resultado? Podemos ver abaixo no GIF:
Conclusão
Essa é apenas uma pequena dica para desenvolvedores que estão com problemas de performance em casos extremos, onde possuem muitas rotas e muitas são acessadas na aplicação web. Vou disponibilizar o link abaixo do GitHub com o repositório do projeto. Ele está em Angular 12. Fico por aqui e até a próxima! 😄
Repo: github.com/rafaelsmiguelsantos/angular-load..
Referências:
Angular Documentation: angular.io/api/router/PreloadingStrategy
Blog Medium: blog.devgenius.io/advanced-preloading-strat..