Promises em JavaScript: o que são e como funcionam na prática

Se você está aprendendo JavaScript e já começou a consumir APIs ou trabalhar com requisições assíncronas, é essencial entender o que são as Promises em JavaScript.

Neste artigo, vamos descomplicar o conceito de Promises, explicar como elas funcionam na prática, mostrar exemplos reais e te ajudar a dominar uma das ferramentas mais importantes para quem desenvolve com JavaScript moderno.

O que são Promises em JavaScript?

As Promises são objetos nativos do JavaScript que representam operações assíncronas — ou seja, tarefas que não são executadas imediatamente e que podem levar algum tempo para finalizar, como ler um arquivo, buscar dados de uma API ou esperar uma resposta do servidor.

Uma Promise tem três estados possíveis:

  • Pending (pendente): quando a operação ainda está em andamento;
  • Fulfilled (realizada): quando a operação foi concluída com sucesso;
  • Rejected (rejeitada): quando a operação falhou.
Promises em javascript: Os três estados possíveis de uma promise

Em vez de depender de callbacks encadeados (o famoso “callback hell”), as Promises permitem escrever um código mais limpo e fácil de entender, com .then() e .catch().

Sintaxe básica de uma Promise

Aqui está um exemplo simples de uma Promise:

const minhaPromise = new Promise((resolve, reject) => {
  const sucesso = true;

  if (sucesso) {
    resolve('Operação realizada com sucesso');
  } else {
    reject('Houve um erro na operação');
  }
});

minhaPromise
  .then(resultado => console.log(resultado))
  .catch(erro => console.error(erro));

Explicação passo a passo:

  1. Criação da Promise:const minhaPromise = new Promise((resolve, reject) => { ... });Aqui, você está criando uma nova Promise. Ela recebe uma função com dois parâmetros: resolve (para quando der certo) e reject (para quando der errado).
  2. Simulação do resultado:const sucesso = true;A constante sucesso simula se a operação foi bem-sucedida ou não. Se true, chama resolve; se false, chama reject.
  3. Execução com then/catch:minhaPromise.then(resultado => console.log(resultado)) .catch(erro => console.error(erro));Aqui, você trata o resultado da Promise:
    • .then() será chamado se a Promise for resolvida com sucesso.
    • .catch() será chamado se houver um erro (Promise rejeitada).

No exemplo acima, como sucesso é true, o console imprimirá:

Operação realizada com sucesso

Se mudar sucesso para false, o console mostrará:

Houve um erro na operação

Esse é o comportamento básico de uma Promise: permitir que você controle fluxos assíncronos de forma clara e elegante.

Promises na prática: simulando uma requisição

Para consolidar o conceito de Promises em JavaScript, vamos aplicar esse conhecimento em um exemplo prático.

Vamos simular um cenário real: imagine um sistema que precisa carregar os comentários de um post de blog, o que pode levar cerca de 2 segundos em uma rede mais lenta ou com servidor congestionado.

Esse é um ótimo exemplo de onde uma Promise seria aplicada para lidar com essa latência de forma controlada.

📌 Exemplo de código: Carregando comentários de um post de blog com atraso simulado:

function carregarComentarios(postId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([ 
        { autor: 'Ana', comentario: 'Ótimo post!' },
        { autor: 'Carlos', comentario: 'Muito útil, obrigado!' },
        { autor: 'Júlia', comentario: 'Salvou meu projeto :)' }
      ]);
    }, 2000);
  });
}

carregarComentarios(101)
  .then(comentarios => {
    comentarios.forEach(c => {
      console.log(`${c.autor}: ${c.comentario}`);
    });
  });

Nesse exemplo, usamos setTimeout() para simular o tempo de resposta de uma API. Quando o tempo passa, a Promise é resolvida com a lista de nomes. Na vida real, este seria o tempo em que o servidor backend processa os dados e retorna o objeto JSON para o frontend (Javascript). 

Lidando com erros usando .catch()

Agora que você viu como simular uma requisição para carregar comentários, é hora de entender como capturar e lidar com erros nesse processo. Afinal, em uma aplicação real, a API pode falhar, o servidor pode estar fora do ar ou o conteúdo pode não existir. Vamos ver como tratar esses cenários usando Promises.

Se algo der errado durante a execução da Promise, podemos capturar o erro com .catch():

📌 Exemplo com falha na requisição de comentários:

function carregarComentarios(postId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const sucesso = false;

      if (sucesso) {
        resolve([
          { autor: 'Ana', comentario: 'Ótimo post!' },
          { autor: 'Carlos', comentario: 'Muito útil, obrigado!' }
        ]);
      } else {
        reject('Erro ao buscar comentários do post');
      }
    }, 2000);
  });
}

carregarComentarios(101)
  .then(comentarios => {
    comentarios.forEach(c => console.log(`${c.autor}: ${c.comentario}`));
  })
  .catch(erro => {
    console.error('Falha ao carregar:', erro);
  });

Nesse exemplo, a flag sucesso está definida como false, simulando uma falha na requisição. O método .catch() é responsável por capturar e exibir a mensagem de erro no console, algo essencial para aplicações mais robustas.

Para quem vem de linguagens como PHP, Java ou C#, o método .catch() tem uma função semelhante ao bloco try-catch tradicional: ele permite capturar exceções e tratar erros de forma segura e previsível no fluxo assíncrono.

Promise chaining: encadeando promises em Javascript

Dando continuidade ao exemplo do carregamento de comentários do blog, imagine que você queira exibir os comentários somente após verificar se o post ainda está ativo. Essa verificação e o carregamento podem ser feitas em etapas separadas, encadeando Promises para manter o código organizado e fácil de ler.

📌 Exemplo prático de encadeamento com base no carregamento de comentários:

Imagine que você precisa primeiro verificar se o post está ativo antes de buscar os comentários. Podemos encadear essas duas ações usando Promises:

function verificarPostAtivo(postId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const ativo = true;

      if (ativo) {
        resolve(postId);
      } else {
        reject('O post está inativo');
      }
    }, 1000);
  });
}

function carregarComentarios(postId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        { autor: 'Ana', comentario: 'Ótimo post!' },
        { autor: 'Carlos', comentario: 'Muito útil, obrigado!' }
      ]);
    }, 2000);
  });
}

verificarPostAtivo(101)
  .then(carregarComentarios)
  .then(comentarios => {
    comentarios.forEach(c => console.log(`${c.autor}: ${c.comentario}`));
  })
  .catch(erro => console.error('Erro:', erro));

Esse é um dos grandes diferenciais das Promises em JavaScript… a possibilidade de encadear múltiplas operações assíncronas de forma sequencial e organizada. 

Neste exemplo, verificarPostAtivo() retorna uma Promise que valida se o post ainda está disponível. Se estiver, a função carregarComentarios() é executada em seguida, utilizando o resultado da etapa anterior. Caso alguma das etapas falhe, o erro será capturado no .catch().

Por que Promises são importantes para devs iniciantes

Entender Promises em JavaScript é essencial para evoluir na carreira como dev front-end ou full stack. Elas estão por trás de grande parte das integrações com APIs, carregamento de dados e operações assíncronas.

Um ótimo exemplo disso é o carregamento de comentários em um post de blog, onde é necessário aguardar uma resposta da API antes de exibir o conteúdo na tela.

Esse mesmo conceito também se aplica em diversos outros contextos no mercado de trabalho, como consultas a serviços de pagamento, verificação de status de pedidos ou autenticação de usuários em sistemas externos.

Além disso, Promises são a base para compreender async/await, que veremos nos próximos conteúdos da trilha.

Leia também

Links úteis e externos para aprofundar sobre Promises em Javascript

Conclusão

As Promises em JavaScript são fundamentais para lidar com tarefas assíncronas, e dominar seu uso vai te preparar para criar aplicações mais robustas, organizadas e responsivas.

No próximo artigo da trilha, vamos explorar o uso de async e await, que tornam o uso de Promises ainda mais fluido.

📲 Não perca os próximos conteúdos! Siga nosso canal exclusivo no Instagram para acompanhar a trilha completa.

Foto de Diogo Pé

Diogo Pé

Autor e criador do Programadores Brasil

Posts Relacionados