Observables: como funcionam?
Tags: angular, javascript, rxjs
Published: 2019-06-24 17:07:32

##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()**.

```typescript
  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**.

```typescript
  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.

```typescript
  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.

```typescript
  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).

{% stackblitz fdsc-angular-observables %}

Caso não consiga ver o embedded, clique [aqui](https://stackblitz.com/edit/fdsc-angular-observables). 

###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!](https://dev.to/felipedsc/observables-cancelar-inscricao-unsubscribe-e-importante-51bc)