Promise ou Observable? Quais as diferenças?

Muitos desenvolvedores (inclusive eu) acabam se confundindo o uso de promises e o de observables. Por esse motivo resolvi fazer esse post com exemplos e explicações detalhadas sobre cada um deles.

O que é uma promise?

A promise é uma abstração para representar fluxos de ações em códigos assíncronos. No JavaScript é um objeto e seu resultado representa uma operação assíncrona ela pode ser resolvida ou rejeitada.

A promise possui duas maneiras para retornar a informação, são as funções de callback resolve e reject. As duas chamam métodos retornados junto a promise. Os métodos then e catch, são retornados juntos a promise e eles são responsáveis por receber os métodos de callback para a operação.

Exemplos de uma promise:

// ATENÇÃO: Exemplo em javascript puro.
saldoConta = 100;
function sacar(valor) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            if (saldoConta < valor) {
                reject("Você não possui saldo suficiente");
            } else {
                saldoConta = saldoConta - valor;
                resolve("Saldo retirado com sucesso");
            }
        }, 3000);
    });
}

// agora vamos sacar 90 reais?
sacar(90).then(function(r) {
    alert('sucesso: ' + r);
}).catch(function(e) {
    alert('erro: ' + e);
});

// agora vamos sacar mais 11 reais?
sacar(11).then(function(r) {
    alert('sucesso: ' + r);
}).catch(function(e) {
    alert('erro: ' + e);
});

É simples assim, a promessa resolve ou rejeita sua solicitação.

O que é um Observable?

[wp_ad_camp_3]

Observables fornecem suporte para a transmissão de mensagens entre editores e assinantes em seu aplicativo. Os observables ​​oferecem benefícios significativos em relação a outras técnicas para manipulação de eventos, programação assíncrona e manipulação de vários valores.

Os observables ​​são declarativos – isto é, você define uma função para publicar valores, mas não é executado até que um consumidor assine a ele. O consumidor inscrito recebe notificações até que a função seja concluída ou até que elas sejam canceladas.

Um observable pode fornecer vários valores de qualquer tipo – literais, mensagens ou eventos, dependendo do contexto. A API para receber valores é a mesma, quer os valores sejam entregues de forma síncrona ou assíncrona. Como a lógica de configuração e de desmontagem são tratadas pelo observable, o código do seu aplicativo só precisa se preocupar em se inscrever para consumir valores e, quando terminar, desinscrever. Vou deixar abaixo o exemplo de um Observable para escutar mudança da posição geográfica do usuário usando a API geolocation.

// Cria um Observable que ouve as atualizações de geolocalização
// quando um consumidor se inscreve
const locations = new Observable((observer) => {
	// Obtenha os próximos retornos de chamada e erros. Estes serão passados quando
	// o consumidor assina.
	const {
		next,
		error
	} = observer;
	let watchId;

	// a API geolocation checa valores para publicar.
	if ('geolocation' in navigator) {
		watchId = navigator.geolocation.watchPosition(next, error);
	} else {
		error('Geolocation not available');
	}

	// Quando o consumidor cancelar a assinatura, limpe os dados prontos para a próxima assinatura.
	return {
		unsubscribe() {
			navigator.geolocation.clearWatch(watchId);
		}
	};
});

// Chame o subscribe() para ouvir as atualizações.
const locationsSubscription = locations.subscribe({
	next(position) {
		console.log('Posição Atual: ', position);
	},
	error(msg) {
		console.log('Erro ao recuperar localização: ', msg);
	}
});

// Para de ouvir após 10 segundos
setTimeout(() => {
	locationsSubscription.unsubscribe();
}, 10000);

Requisições HTTP

[wp_ad_camp_2]

Agora que já vimos sobre promises e sobre os observables, vamos imaginar eles aplicados em uma requisição HTTP. Saindo um pouquinho da caixa, requisições HTTP são utilizadas constantemente (obvio né? kkk) elas além de resolver e rejeitar tem uma série de fatores que podem acontecer em seu ambiente externo ou interno que necessitam de tratativas especiais.

Requisições HTTP podem falhar por problemas de conexão, requisições HTTP podem nos informar sobre seu progresso, requisições HTTP podem ser canceladas…

Sua requisição falhou, e agora?

Podemos dizer que é comum termos requisições que não são concluídas, quando isso ocorre geralmente mostramos um erro para o usuário ou então implementamos algum método para tentar novamente. Com o observable podemos tratar isso facilmente com o operador “retry”, com ele podemos especificar quantas vezes nosso observable pode tentar refazer a requisição. Legal né?

O usuário saiu da tela antes da requisição se completar, e agora?

É muito comum o usuário cancelar uma ação, seja por erro dele, ou por demora em obter a resposta, ele pode e com certeza ele vai sair da sua operação para tentar novamente. Como você iria cancelar essa operação caso esteja fazendo uso de uma promise? Para isso você teria que fazer alguma implementação externa ou usar algum framework para facilitar a operação. Já com observable você pode simplesmente chamar o operador “unsubscribe” e pronto, você já não está mais esperando uma resposta.

Conclusão

[wp_ad_camp_1]

O observable tem mais vantagens que as promises, e você pode definir quando deseja usar cada um dos recursos. Sobre o observable sua grande vantagem está nos “poderes” que ele nos dá com seus operadores. No exemplo acima ao cancelar um request quando o usuário sai da dela, poupou processamento e também conseguimos tratar possíveis problemas de falha, como o retry na perda de conexão. Já com promises é possível cancelar, e fazer os retry mas não usando sua definição e sim usando meios/frameworks alternativos.

Fontes:

  1. Entendendo RxJS Observable com Angular
  2. Promises em Javascript
  3. Angular – Observables

 

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *