Promises em JavaScript: Conceitos Essenciais e Personalização

Conceitos Fundamentais

Promises são objetos que representam a eventual conclusão ou falha de uma operação assíncrona. Elas permitem o encadeamento de callbacks de forma mais legível, evitando o "callback hell". O construtor Promise aceita uma função executora com dois argumentos: resolve para sucesso e reject para falha.

Implementação Básica

const minhaPromessa = new Promise((resolucao, rejeicao) => {
    // Exemplo condicional
    const condicao = Math.random() > 0.5;
    if (condicao) {
        resolucao('Operação bem-sucedida');
    } else {
        rejeicao('Erro na operação');
    }
});

minhaPromessa.then(
    resultado => console.log(resultado),
    erro => console.error(erro)
);

Casos de Uso Iniciais

1. Leitura de Arquivos com Módulo fs

const fs = require('fs');
const caminhoArquivo = './dados.txt';

function lerArquivoComPromessa(caminho) {
    return new Promise((sucesso, falha) => {
        fs.readFile(caminho, 'utf8', (erro, conteudo) => {
            if (erro) falha(erro);
            else sucesso(conteudo);
        });
    });
}

lerArquivoComPromessa(caminhoArquivo)
    .then(dados => console.log('Conteúdo:', dados))
    .catch(err => console.error('Erro:', err));

2. Requisição Ajax com XMLHttpRequest


<html>
<head>
    <title>Exemplo Ajax com Promise</title>
</head>
<body>
    <button id="btnSolicitar">Carregar Dados</button>
    <script>
        document.getElementById('btnSolicitar').addEventListener('click', () => {
            const promessaAjax = new Promise((resolver, rejeitar) => {
                const xhr = new XMLHttpRequest();
                xhr.open('GET', 'https://api.exemplo.com/dados');
                xhr.onload = () => {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        resolver(xhr.responseText);
                    } else {
                        rejeitar(new Error(`Status: ${xhr.status}`));
                    }
                };
                xhr.onerror = () => rejeitar(new Error('Erro de rede'));
                xhr.send();
            });
            
            promessaAjax
                .then(dados => console.log('Resposta:', dados))
                .catch(err => console.error('Falha:', err));
        });
    </script>
</body>
</html>

3. Função Genérica para Ajax

function obterDados(url) {
    return new Promise((aceitar, recusar) => {
        const conexao = new XMLHttpRequest();
        conexao.open('GET', url);
        conexao.onload = function() {
            this.status >= 200 && this.status < 300
                ? aceitar(this.response)
                : recusar(this.status);
        };
        conexao.send();
    });
}

obterDados('https://api.exemplo.com/info').then(console.log).catch(console.error);

Conversão para Estilo Promise

O módulo util do Node.js oferece promisify para transformar funções com callback de erro em versões baseaads em Promises.

const util = require('util');
const fs = require('fs');
const lerArquivoPromisificado = util.promisify(fs.readFile);

lerArquivoPromisificado('./config.json', 'utf8')
    .then(conteudo => console.log(JSON.parse(conteudo)))
    .catch(erro => console.error('Falha na leitura:', erro));

Propriedades de uma Promise

  • Estado (PromiseState): Pode ser pendente, resolvida ou rejeitada.
  • Resultado (PromiseResult): Armazena o valor da resolução ou o motivo da rejeição.

API de Promises

  1. new Promise(executor): Executor é chamado imediatamente de forma síncrona.
  2. Promise.prototype.then(onFulfilled, onRejected): Retorna uma nova Promise.
  3. Promise.prototype.catch(onRejected): Atalho para tratar rejeições.
  4. Promise.resolve(valor): Cria uma Promise resolvida. Se valor for uma Promise, retorna-a.
  5. Promise.reject(razao): Cria uma Promise rejeitdaa com o valor fornecido.
  6. Promise.all(iteravel): Resolve quando todas as Promises no iterável resolvem. Rejeita na primeira rejeição.
  7. Promise.race(iteravel): Resolve ou rejeita com o resultado da primeira Promise a mudar de estado.

Tópicos Avançados e Perguntas Comuns

Alterando Estados de uma Promise

Uma Promise pode ter seu estado alterado por: chamada de resolve, chamada de reject ou lançamento de um erro dentro do executor.

Múltiplos Callbacks em uma Promise

const promessaMultipla = new Promise(resolve => resolve('valor'));

promessaMultipla.then(v => console.log('Callback 1:', v));
promessaMultipla.then(v => console.log('Callback 2:', v));
// Ambos os callbacks são executados

Encadeamento de Operações

const tarefaAssincrona = () => new Promise(resolve => 
    setTimeout(() => resolve('Passo 1 concluído'), 100)
);

tarefaAssincrona()
    .then(msg => {
        console.log(msg);
        return new Promise(resolve => resolve('Passo 2'));
    })
    .then(resultado => console.log(resultado))
    .then(() => console.log('Passo 3')); // Resultado undefined se não houver retorno

Propagação de Erros

Em uma cadeia de then, erros são capturados pelo próximo catch ou tratamento de rejeição.

Interrompendo a Cadeia

Retorne uma Promise pendente dentro de um then para pausar o encadeamento:

function processarDados() {
    return new Promise(() => {}); // Promise pendente
}

Promise.resolve('inicio')
    .then(processarDados)
    .then(() => console.log('Isso não será executado'));

Tags: javascript promise Async/Await Node.js XMLHttpRequest

Publicado em 7-3 20:42