Observables: como funcionam?
Felipe Carvalho
Posted on June 24, 2019
Introdução
Observable é uma funcionalidade da biblioteca rxjs, que é utilizada internamente pelo framework e já é instalada quando você cria uma nova aplicação Angular. Com Observables, conseguimos lidar com transferência de dados assíncrona. Muitas vezes, seu uso é semelhante ao de Promises do Javascript, porém, podendo ser uma fonte de transferência de dados contínua, ou seja, o Observable poderá emitir dados várias vezes em momentos distintos de sua existência.
Uso
Seu uso consiste em basicamente se inscrever (subscribe) à um Observable, informando o que deverá ser feito com o dado que irá receber. Essa inscrição poderá escutar 3 interações: sucesso, erro e completo (encerrado). Podemos informar no próprio subscribe, via parâmetro, as funções que devem ser executadas quando alguma dessas interações ocorrerem, sendo somente função de sucesso obrigatória.
É importante ter em mente que ao emitir um erro, o Observable sempre encerrará sua execução, podendo passar algum dado. Ao completar, ele apenas encerra a execução, sem passar nenhum dado para os inscritos, apenas os informa que ele completou seu ciclo.
Podemos nos inscrever ao mesmo Observable mais de uma vez e em vários pontos da aplicação, tornado-os uma excelente alternativa para comunicação entre componentes, o que recomendo ser feito com usando Subject ou BehaviorSubject, que derivam de Observables e têm rápida implementação. Deixarei para abordá-los em outro post.
Resumo
Resumidamente, com um Observable podemos:
• Receber dados várias vezes e em vários momentos
• Nos inscrever para receber dados de um mesmo Observable em vários pontos da aplicação
• Executar alguma operação quando o dado for recebido com sucesso
• Executar alguma operação quando emitir erro
• Executar alguma operação quando completar
Exemplo
Não é tão comum criar Observables “puros”, mas acredito que seja a melhor maneira para entender o seu funcionamento. Detalharei um pouco cada trecho do código e logo após disponibilizarei um exemplo funcional no stackblitz.
No Observable, defini o observador responsável por emitir algum dado para todos os inscritos, observadores, através do método next().
novoObservable(): Observable<string> {
return new Observable<string>(observador => {
setTimeout(() => {
observador.next("Primeiro timeout");
}, 2000);
setTimeout(() => {
observador.next("Segundo timeout");
}, 3000);
setTimeout(() => {
observador.next("Terceiro timeout");
}, 5000);
setTimeout(() => {
observador.next("Quarto timeout");
}, 4000);
});
}
Para receber os dados do Observable é necessário se inscrever nele através do método subscribe(). No ngOnInit() do meu componente, me inscrevi no Observable criado anteriormente, passando como parâmetro as funções de sucesso, erro e encerramento. Basicamente, irei adicionar a uma lista os resultados emitidos para exibi-la na tela. Chamamos isso de uma Subscription.
ngOnInit() {
const observable = this.novoObservable();
this.inscricaoObservable = observable.subscribe(
valor => {
this.valoresRecebidos.push(valor);
},
erro => {
this.valoresRecebidos.push(erro);
},
() => {
this.valoresRecebidos.push("O observable foi encerrado!");
});
}
Além do método next(), temos o error(), ao qual, no exemplo abaixo, passo uma mensagem de erro que, da mesma forma que passo dados através do next(), o Observable a emitirá à todos observadores.
Disparei um erro no Segundo timeout, o que irá interromper o Observable antes de emitir o Terceiro e Quarto timeouts. Isso acionará a segunda função que passamos por parâmetro na nossa Subscription, adicionando o resultado "Erro no observable!" à nossa lista de valores recebidos.
novoObservable(): Observable<string> {
return new Observable<string>(observador => {
setTimeout(() => {
observador.next("Primeiro timeout");
}, 2000);
setTimeout(() => {
observador.next("Segundo timeout");
observador.error("Erro no observable!");
}, 3000);
setTimeout(() => {
observador.next("Terceiro timeout");
}, 5000);
setTimeout(() => {
observador.next("Quarto timeout");
}, 4000);
});
}
Por fim, o observador também disponibiliza o método complete(), que aciona a terceira função que passamos por parâmetro, encerrando o Observable no mesmo instante, porém, sem passar nenhuma informação. O valor a ser inserido na lista de valores foi definido na própria função.
novoObservable(): Observable<string> {
return new Observable<string>(observador => {
setTimeout(() => {
observador.next("Primeiro timeout");
}, 2000);
setTimeout(() => {
observador.next("Segundo timeout");
observador.complete();
}, 3000);
setTimeout(() => {
observador.next("Terceiro timeout");
}, 5000);
setTimeout(() => {
observador.next("Quarto timeout");
}, 4000);
});
}
Veja funcionando:
Para testar o exemplo, talvez seja necessário atualizar o navegador que ele disponibiliza. Remova os os trechos comentados (Ctrl K, U) da criação do Observable e repare que quando um error() ou complete() são acionados, o Observable é interrompido e não emite todos os dados. Experimente também remover as funções que passamos por parâmetro para o Observable, deixando apenas a de sucesso (primeira).
Caso não consiga ver o embedded, clique aqui.
Cancelar inscrição!
Repare que também criei a variável chamada Subscription no exemplo anterior. Se desinscrever dos Observables é uma boa prática que deve não deve ser esquecida!
Mais detalhes neste post: Observables: Cancelar inscrição (unsubscribe) é importante!
Posted on June 24, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 24, 2024