Estratégia de pré-carregamento preditiva para seus pacotes angulares

John Papa Segue 31 de maio · 6 min ler

Os usuários querem aplicativos rápidos. Colocar seus pacotes JavaScript em seu navegador o mais rápido possível e antes que o usuário precise deles pode ter um impacto enorme e positivo na experiência do usuário. Saber como você pode melhorar essa experiência é importante.

Uma forma de melhorar a experiência do usuário com seus aplicativos angulares é decidir estrategicamente quais pacotes serão pré-carregados. Você controla quando os pacotes são carregados e quais pacotes são carregados. É por isso que você deve explorar a possibilidade de escolher um modelo embutido ou criar sua própria estratégia personalizada de pré-carregamento Angular.

Nesta série, exploraremos algumas das suas opções para pré-carregar bundles angulares.

Aqui estão os artigos desta série:

Escotismo à frente

A estratégia "on demand" pré-carrega uma ou mais rotas quando um usuário executa uma ação específica. Você decide qual ação fará com que uma rota seja pré-carregada. Por exemplo, você pode configurar isso para pré-carregar uma rota enquanto um usuário passa por cima de um botão ou item de menu.

Você pode criar o OnDemandPreloadService personalizado criando uma classe que implemente a interface PreloadingStrategy e forneça-a na raiz. Em seguida, você deve implementar a função de preloadpreload e retornar a função load() quando quiser informar ao Angular para pré-carregar a função.

Observe que a função de preloadpreload na classe OnDemandPreloadService examina o Observable preloadOnDemand$ . Ele canaliza o observável e usa o operador mergeMap RxJs para alternar para um novo Observable. Esse novo valor do Observable depende da função local preloadCheck .

A função preloadCheck verifica se o preloadOptions (que vem do Observable original) tem um routePath que corresponde a uma rota que possui a propriedade data.preload definida como true . Então, aqui estamos optando por algumas das rotas no pré-carregamento e deixando algumas rotas a serem carregadas quando elas são solicitadas explicitamente.

 @Injectable ({providedIn: 'root', deps: [OnDemandPreloadService]}) 
classe de exportação OnDemandPreloadStrategy implementa PreloadingStrategy {
private preloadOnDemand $: Observable <OnDemandPreloadOptions>;
construtor (private preloadOnDemandService: OnDemandPreloadService) {
this.preloadOnDemand $ = this.preloadOnDemandService.state;
}
preload (route: Route, load: () => Observável <qualquer>): Observable <any> {
return this.preloadOnDemand $ .pipe (
mergeMap (preloadOptions => {
const shouldPreload = this.preloadCheck (rota, preloadOptions);
devolver shouldPreload? load (): EMPTY;
})
);
}
private preloadCheck (route: Rota, preloadOptions: OnDemandPreloadOptions) {
Retorna (
route.data &&
route.data ['preload'] &&
[route.path, '*']. inclui (preloadOptions.routePath) &&
preloadOptions.preload
);
}
}

Definições de rota

Essa estratégia requer que você indique quais rotas podem ser pré-carregadas. Você pode fazer isso adicionando a propriedade data.preload e definindo-a como true em sua definição de rota, conforme mostrado abaixo.

 exportar rotas const: rotas = [ 
{path: '', pathMatch: 'full', redirectTo: 'heroes'},
{
caminho: 'dashboard',
loadChildren: () =>
import ('app / dashboard / dashboard.module'). então (m => m.DashboardModule),
data: {preload: true}
}
{
caminho: 'heróis',
loadChildren: () =>
import ('app / heroes / heroes.module'). então (m => m.HeroesModule),
data: {preload: true}
}
{
caminho: 'vilões',
loadChildren: () =>
import ('app / villains / villains.module'). então (m => m.VillainsModule)
}
{path: '**', pathMatch: 'full', componente: PageNotFoundComponent}
];

Observe que o painel e os heróis fazem o preload.data ambos, com a propriedade preload.data definida como true . No entanto, a rota dos vilões não tem esse conjunto de propriedades. Nesse cenário, os heróis e o painel de controle têm o pré-carregamento ativado, mas os vilões só carregam quando o usuário navega para essa rota.

Configurando o Custom OnDemandPreloadService

Então, quando a criação de seu RouterModule , passar as opções do roteador, incluindo a preloadingStrategy ao forRoot() função.

 @NgModule ({ 
importações: [
RouterModule.forRoot (routes, {
preloadingStrategy: OnDemandPreloadService
})
]
exportações: [RouterModule]
})
classe de exportação AppRoutingModule {}

Decidindo quando pré-carregar

A peça que falta aqui é o mecanismo que você usa para informar ao aplicativo qual rota deve ser pré-carregada e quando pré-carregá-la. Observe o serviço OnDemandPreloadService no código abaixo. Você pode chamar a função startPreload deste serviço e passar a rota que deseja pré-carregar. O serviço OnDemandPreloadService , em seguida, é o assunto seguinte (pense nisso como publicar ou emitir uma mensagem). Então quem ou o que quer que ouça a mensagem pode agir sobre ela.

É aí que entra a estratégia OnDemandPreloadStrategy , como está escutando.

 classe de exportação OnDemandPreloadOptions { 
construtor (public routePath: string, public preload = true) {}
}
@Injectable ({providedIn: 'root'})
classe de exportação OnDemandPreloadService {
assunto particular = novo Assunto <OnDemandPreloadOptions> ();
estado = this.subject.asObservable ();
startPreload (routePath: string) {
const message = new OnDemandPreloadOptions (routePath, true);
this.subject.next (mensagem);
}
}

Vincular a um evento de mouseover

Agora seu aplicativo está pronto para pré-carregar uma rota quando você decidir fazer isso. Você pode tentar isso vinculando um evento DOM como mouseover e disparando a função startPreload do OnDemandPreloadService .

 <a 
[routerLink] = "item.link"
class = "nav-link"
(mouseover) = "preloadBundle ('heroes')"
> heróis </ a
>

Observe que o código a seguir aceita o caminho da rota e o transmite para a função preloadOnDemandService.startPreload .

 preloadBundle (routePath) { 
this.preloadOnDemandService.startPreload (routePath);
}

Todos juntos

Vamos voltar e seguir como tudo isso funciona.

  1. Um usuário passa o mouse sobre sua tag de âncora
  2. A ligação mouseover chama uma função em seu componente, passando o caminho da rota ('heroes' neste caso)
  3. Esse código chama o PreloadOnDemandService serviço startPreload , passando o caminho da rota para ele
  4. O serviço PreloadOnDemandService ao lado do Assunto RxJS, que é exposto como um Observable
  5. O OnDemandPreloadStrategy recebe um identificador desse Observable, e ele sabe quando "nexts"
  6. O OnDemandPreloadStrategy canaliza para o mergeMap e avalia a rota para o pré-carregamento
  7. Se decidir pré-carregar, o OnDemandPreloadStrategy retorna um novo Observable com a função load()
  8. Se ele decidir não pré-carregar, o OnDemandPreloadStrategy retornará um Observable com o EMPTY observable (que não pré-carrega)
  9. O roteador Angular ouve a resposta da função de preload da estratégia e pré-carrega ou não, de acordo.

Tente

Depois de aplicar essa estratégia, reconstrua e execute seu aplicativo com ng serve . Abra seu navegador, abra suas ferramentas de desenvolvedor e vá para http://localhost:4200 . Quando você inspeciona a guia Rede no seu navegador, provavelmente não verá nenhum de seus pacotes pré-carregados (exceto o roteamento por onde você navegou por padrão, se o carregamento for lento).

Em seguida, passe o mouse sobre o elemento HTML onde ele é acionado com o evento mouseover que você vinculou. Verifique sua guia de rede no seu navegador e você verá que o pacote será pré-carregado.

Decidindo o que é certo para o seu aplicativo

Agora que você sabe como criar sua própria estratégia de pré-carregamento, como OnDemandPreloadService , como avaliar se essa é a estratégia correta para seu aplicativo?

Essa é uma estratégia mais envolvida, com certeza. Poderia ser benéfico para seus usuários? Seus usuários costumam passar o mouse sobre os resultados da pesquisa antes de selecioná-los? Isso normalmente dispararia um pacote preguiçoso? Se assim for, talvez isso possa dar um impulso inicial à pré-carga.

Se você puder determinar que o comportamento e o fluxo de trabalho de seus usuários geralmente seguem um caminho específico antes de carregar um novo pacote, essa estratégia pode ser benéfica.

Você pode aplicar isso a vários cenários, como passar o mouse sobre um elemento HTML, clicar em um botão ou rolar para uma área específica da tela.

No final, a decisão depende de você. Eu recomendo antes de escolher essas opções, ou qualquer estratégia de pré-carregamento, que você teste em várias velocidades de rede sob vários fluxos de trabalho de usuário válidos e comuns. Esses dados ajudarão você a decidir se essa é a estratégia certa para você ou se outra pode ser mais benéfica para os usuários do seu aplicativo.

Recursos

Originalmente publicado em johnpapa.net em 31 de maio de 2019.