// js · Web Platform Advent #2
Promises em JavaScript: um guia prático
Entenda as promises em JavaScript — como criá-las, then/catch/finally, encadeamento e combinar várias com Promise.all, race, any e allSettled — com exemplos executáveis e as armadilhas mais comuns.
Uma promise é um objeto que representa um valor que ainda não está pronto. É a base do JavaScript assíncrono: fetch(), temporizadores, leituras de arquivos no Node e a maioria das APIs modernas retornam promises. Uma promise está sempre em um de três estados — pendente, resolvida ou rejeitada — e, uma vez decidida, nunca mais muda.
Criar uma promise
Na maior parte do tempo você consome promises que uma API lhe entrega. Mas você cria uma você mesmo com o construtor Promise, que recebe uma função executor que recebe resolve e reject:
const wait = (ms) => new Promise((resolve) => {
setTimeout(resolve, ms);
});
const fetchUser = (id) => new Promise((resolve, reject) => {
if (!id) reject(new Error('id is required'));
else resolve({ id, name: 'Ada' });
}); Chamar resolve(value) resolve a promise com esse valor; chamar reject(error) a rejeita. Qualquer coisa lançada de forma síncrona dentro do executor também rejeita a promise.
then, catch e finally
Você lê o resultado de uma promise com .then() para o sucesso, .catch() para a falha e .finally() para a limpeza que roda de qualquer forma:
fetchUser(42)
.then((user) => console.log('Got', user.name))
.catch((err) => console.error('Failed:', err.message))
.finally(() => console.log('Done')); .then() pode receber dois argumentos — onFulfilled e onRejected — mas um .catch() separado no fim da cadeia é mais claro e também captura erros lançados dentro de manipuladores .then() anteriores.
Encadeamento: o verdadeiro superpoder
Cada .then() retorna uma nova promise, então elas se encadeiam. O que você retornar de um manipulador torna-se a entrada do próximo. Crucialmente, se você retornar uma promise, a cadeia aguarda que ela seja decidida antes de continuar:
fetch('/api/user')
.then((res) => res.json()) // returns a promise → chain waits
.then((user) => fetch('/api/posts?user=' + user.id))
.then((res) => res.json())
.then((posts) => console.log(posts.length, 'posts'))
.catch((err) => console.error(err)); Um único .catch() no final trata uma rejeição de qualquer passo acima dele, e é por isso que o encadeamento supera o aninhamento de callbacks.
Executar promises em conjunto
Quando as tarefas não dependem umas das outras, inicie-as em paralelo e combine os resultados. Quatro métodos estáticos cobrem os casos mais comuns:
Promise.all([...])— aguarda que todas sejam resolvidas; é rejeitada assim que uma for rejeitada. Retorna um array de resultados em ordem.Promise.allSettled([...])— aguarda que todas terminem e nunca é rejeitada; retorna um array de objetos{ status, value }ou{ status, reason }.Promise.race([...])— é decidida com a primeira promise a ser decidida, seja ela resolvida ou rejeitada.Promise.any([...])— é decidida com a primeira promise a ser resolvida; só é rejeitada se todas forem rejeitadas.
// Fetch three resources at once, fail if any fails
const [user, posts, prefs] = await Promise.all([
fetch('/api/user').then((r) => r.json()),
fetch('/api/posts').then((r) => r.json()),
fetch('/api/prefs').then((r) => r.json()),
]);
// Same, but tolerate individual failures
const results = await Promise.allSettled([taskA(), taskB(), taskC()]);
results.forEach((r) => {
if (r.status === 'fulfilled') console.log('ok', r.value);
else console.warn('failed', r.reason);
}); Armadilhas comuns
- Esquecer o return. Dentro de um
.then(), se você chamar uma promise mas não a retornar comreturn, a cadeia não vai esperá-la — você perde a ordenação e o tratamento de erros. - Rejeições não tratadas. Uma promise sem
.catch()(ou umtry/catchem torno deawait) produz umunhandledrejection. Trate sempre os erros no fim da cadeia. - Misturar callbacks e promises. Não chame
resolveduas vezes nem ambosresolveereject— só a primeira chamada conta; as demais são ignoradas silenciosamente. - O executor roda imediatamente. A função que você passa para
new Promise()roda de forma síncrona, na hora — apenas as callbacks de.then()são adiadas.
Referência rápida
| Objetivo | Método |
|---|---|
| Tratar o sucesso | .then(onFulfilled) |
| Tratar a falha | .catch(onRejected) |
| Limpeza de qualquer forma | .finally(fn) |
| Todas devem ter sucesso | Promise.all |
| Coletar cada resultado | Promise.allSettled |
| A primeira a ser decidida | Promise.race |
| A primeira a ter sucesso | Promise.any |
As promises são o encanamento por baixo de async/await, que é apenas uma sintaxe mais agradável sobre os mesmos objetos. Quando o encadeamento e os quatro combinadores se tornarem naturais, o JavaScript assíncrono deixa de ser intimidante.