Carregando dados iniciais no Angular
É muito comum precisarmos carregar alguns dados antes que uma aplicação web seja iniciada. O exemplo mais recorrente é o de buscar dados do usuário logado via token de acesso. Esta é uma operação assíncrona que ocasiona uma consulta no servidor. Com isso, a aplicação poderá ser iniciada antes que esses dados sejam capturados, ocorrendo em uma experiência ruim para o usuário.
Pensando neste cenário, o framework Angular disponibiliza uma instância de um InjectionToken chamada APP_INITIALIZER. Quando a aplicação for iniciada o Angular se encarrega de executar esta função antes de qualquer outra operação. Se a função retornar uma Promise, o Angular irá aguardar até que ela seja resolvida, agora se ela retornar um Observable, temos também este comportamento até que o mesmo seja completado.
Temos o recurso de declaração de providers no Angular, e graças ao robusto sistema de injeção de dependências, podemos informar dependências em tempo de execução com tokens de injeção, aplicando de forma muito simples o padrão da Inversão de Controle (IoC).
Com isso o Angular nos dá a oportunidade de carregar qualquer função no momento em que o InjectionToken APP_INITIALIZER for disparado. Este é o cenário ideal para carregarmos lógicas assíncronas iniciais.
O primeiro passo é criar um serviço que possui uma função assíncrona. Neste exemplo estamos retornando um Observable que simula uma requisição que demora 5 segundos para ser finalizada.
Agora na declaração dos providers do AppModule realizamos a inversão de controle mencionada anteriormente para que nossa função do serviço seja chamada.
Para isso, foi criada uma Factory Function que recebe como parâmetro o nosso serviço. O objetivo dela é basicamente retornar nossa função assíncrona.
Já no array de providers, declaramos um objeto que provê o APP_INITIALIZER, mas quando ele for executado na verdade será a Factory Function que será invocada por meio do useFactory. Você pode ler mais sobre o useFactory neste artigo. Por fim, vale mencionar o uso da propriedade multi. Deixando ela como true temos a possibilidade de criar outras funções de inicialização com a mesma estratégia de tokens de injeção.
Conclusão
Executando nossa aplicação temos o resultado esperado. Ela só iniciará de fato após 5 segundos. Ou seja, enquanto houver funções a serem finalizadas que estão vinculadas ao APP_INITIALIZER, a aplicação não iniciará. Isso nos garante total integridade dos dados entregues para o usuário final.