Explicando Promises de uma forma didática

viniciusersouza

Vinicius

Posted on March 26, 2019

Explicando Promises de uma forma didática

Introdução

Enquanto escrevemos nossos códigos, diariamente esbarramos - mesmo que de forma inconsciente - no que chamamos de Promises (ou Promessas). As similaridades entre o objeto de uma promise e uma promessa feita no dia-a-dia são maiores do que pensamos quando tratamos pelo fluxo que elas percorrem.

Quando prometemos algo para alguém, podemos cumprir esta promessa ou não. Em JavaScript, esse comportamento é muito parecido. Ao estabelecermos uma promise, este retorno pode ou não se concretizar - e assim definirmos uma decisão para esses casos (resolve ou reject).

Iniciando pelo básico

Digamos que eu faça uma promessa aos meus gatos de alimentá-los todas as manhãs.

Em JavaScript teríamos:

let promessaDeAlimentarGatos = new Promise(function(resolve, reject){
    let poteCheio = true;

    if(poteCheio) {
        resolve('Buchinho cheio');
    } else {
        reject('Fome');
    }
});
Enter fullscreen mode Exit fullscreen mode

Resultado: 'Buchinho cheio'.

Como na vida real, em JavaScript temos dois retornos chamados de resolve e reject. No exemplo acima, por poteCheio ser verdadeiro, meus gatos tiveram mais um dia de barriga cheia e muita preguiça.

Portanto, respeitando as condições, a Promise se resolveu com a mensagem Buchinho cheio. Se poteCheio fosse falso, meus gatos estariam com fome e a Promise rejeitaria com a mensagem Fome.

Onde está a verdadeira utilidade

Como o resultado da Promise depende diretamente de cumprir ou não as condições, temos uma forma de aplicar este resultado fazendo bom uso disso.

Nossa Promise agora existe, então podemos executá-la e exibir uma mensagem de acordo com o resultado obtido, da seguinte forma:

promessaDeAlimentarGatos.then(function(result){
    console.log('Meus gatos estão com ', result)
}).catch(function(result) {
    console.log('Meus gatos estão com ', result);
});
Enter fullscreen mode Exit fullscreen mode

Dissecando este código temos o seguinte fluxo:

  1. Executamos a Promise promessaDeAlimentarGatos
  2. Se o retorno for resolvido (resolve), nossa função .then será ativada e nos mostrará a mensagem 'Meus gatos estão com Buchinho Cheio'.
  3. Se o retorno for rejeitado (reject), nossa função .catch será ativada e nos mostrará a mensagem 'Meus gatos estão com Fome'.

E são as funções .then e .catch que nos trazem uma ótima aplicabilidade do uso das Promises.

Encadeando Promises

Atualmente, tenho 3 gatos. Digamos que quero exibir quais gatos eu já enchi o pote de ração.

Como eu sou só um, eu teria de seguir uma linha para encher todos os potes.

Esta atividade pode ser transcrita para JavaScript da seguinte forma:

let alimentarLuna = function() {
    return new Promise(function(resolve, reject) {
        resolve('Alimentei a Luna');
    });
}

let alimentarJulieta = function(message) {
    return new Promise(function(resolve, reject) {
        resolve(message + ', e' + alimentei a Julieta');
    });
}

let alimentarGatarina = function() {
    return new Promise(function(resolve, reject) {
        resolve(message + ' e ' + alimentei a Gatarina.');
    });
}
Enter fullscreen mode Exit fullscreen mode

Temos acima, três promises que nos retornam quais gatas foram alimentadas. Mas pra isso, eu preciso primeiro encher o pote da primeira gata para passar para o pote da segunda gata.

Podemos transcrever isto para JavaScript da seguinte forma:

alimentarLuna().then(function(result){
    return alimentarJulieta(result);
}).then(function(result){
    return alimentarGatarina(result);
});
Enter fullscreen mode Exit fullscreen mode

O resultado seria impresso na tela desdobrando os resultados das promises

Alimentei a Luna, e alimentei a Julieta e alimentei a Gatarina.

Os resultados das promises foram concatenados e resultaram na frase completa ao fim do processo.

Por que existem as Promises?

Pra isso, precisamos entender que JavaScript é uma linguagem single-threaded, ou seja, trabalha com apenas um caminho - executa apenas uma linha de código em um determinado tempo.

Para que nosso programa não travasse dependendo da resposta de um serviço, elaboramos as Promises - que rodam essa linha de código e convenientemente nos avisam quando esta execução foi encerrada.

Essa discussão pode ficar bem mais aprofundada, mas para nos mantermos no assunto, vou encerrar concluindo que as Promises existem para que os programas em JS possam buscar informações de serviços sem parar a aplicação por inteiro.

Entendendo Promise.all e Promise.raise

As promises não necessariamente precisam rodar em sequência. Podemos, utilizando do exemplo, dividir as tarefas de alimentar as gatas com os outros 2 moradores de minha casa - de forma simultânea.

Assim trataríamos da seguinte forma:

Promise.all([alimentarLuna(), alimentarJulieta(), alimentarGatarina()]).then(function(){
    console.log('Todas as gatas foram alimentadas');
});
Enter fullscreen mode Exit fullscreen mode

Digamos que novas atividades aparecem a medida que os moradores finalizam as suas atividades, podemos usar .raise para notificar quando estas etapas forem se concluindo.

Promise.raise([limparCaixa(), varrerPelos(), trocarAgua()]).then(function(){
    console.log('Um morador finalizou uma das atividades');
});
Enter fullscreen mode Exit fullscreen mode

Conclusão

Resumidamente, as Promises funcionam como nossas promessas. Elas podem ou não se concretizar, e com isso temos tratativas para um final positivo ou negativo deste resultado.

Um breve esquema de como funcionam .then e .catch de acordo com o exemplo dos Gatos alimentados

Utilizar .then e .catch para tratar Promises encadeadas é um daqueles momentos que uma Promise brilha de verdade.

Espero que este breve texto te ajude, e se encontrar algo de errado em minhas palavras, fique a vontade para me corrigir. Atualizarei a publicação sempre que possível.

💖 💪 🙅 🚩
viniciusersouza
Vinicius

Posted on March 26, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related