Misturar código síncrono e assíncrono dentro de uma Promise sempre teve uma armadilha: se a função passada para Promise.resolve() lançar um erro de forma síncrona, esse erro não vira uma rejeição — ele estoura direto, fora da cadeia de .then()/.catch(). O método estático Promise.try() resolve isso: ele executa a função imediatamente e garante que qualquer resultado, erro síncrono ou Promise rejeitada caia sempre no mesmo fluxo.
O problema que ele resolve
Uma forma comum de "elevar" uma função qualquer a uma Promise é envolver a chamada com Promise.resolve(). Só que isso não protege contra um throw síncrono:
function validar(valor) {
if (!valor) throw new Error('valor inválido');
return valor;
}
try {
Promise.resolve(validar(null)).catch(erro => {
console.log('capturado no catch:', erro.message);
});
} catch (erro) {
console.log('escapou para o try/catch síncrono:', erro.message);
// "escapou para o try/catch síncrono: valor inválido"
}
O erro nunca chega ao .catch(), porque validar(null) já lança antes mesmo de Promise.resolve() ser chamado. Para evitar isso, era preciso recorrer a new Promise((resolve) => resolve(validar(valor))), que funciona mas é verboso.
Como funciona o Promise.try()
O método recebe uma função, executa-a de forma síncrona e devolve uma Promise: se ela retornar um valor, a Promise é cumprida com esse valor; se lançar um erro (síncrono ou assíncrono), a Promise é rejeitada:
function validar(valor) {
if (!valor) throw new Error('valor inválido');
return valor;
}
Promise.try(() => validar(null))
.then(valor => console.log('ok:', valor))
.catch(erro => console.log('capturado no catch:', erro.message));
// "capturado no catch: valor inválido"
Não importa se a função é síncrona, assíncrona, retorna um valor direto ou uma Promise — o resultado sempre passa pela mesma cadeia de .then()/.catch().
Funciona igual para funções síncronas e assíncronas
function calcularSincrono() {
return 42;
}
async function calcularAssincrono() {
await new Promise(r => setTimeout(r, 100));
return 42;
}
// Ambas passam pelo mesmo tratamento:
Promise.try(calcularSincrono).then(v => console.log('síncrono:', v));
Promise.try(calcularAssincrono).then(v => console.log('assíncrono:', v));
Isso é útil quando uma API aceita um callback que o usuário pode implementar tanto de forma síncrona quanto assíncrona, e você não quer ter dois caminhos de tratamento de erro diferentes.
Argumentos extras sem criar closure
Promise.try() aceita argumentos adicionais e os repassa direto para a função, evitando a necessidade de uma arrow function só para isso:
function somar(a, b) {
return a + b;
}
// Em vez de:
Promise.try(() => somar(2, 3));
// Pode ser:
Promise.try(somar, 2, 3).then(resultado => console.log(resultado)); // 5
Quando usar
- Envolver funções de terceiros ou de callback que podem lançar de forma síncrona, garantindo que o erro sempre vire uma rejeição tratável.
- Uniformizar o tratamento de erros quando uma função pode ser síncrona ou assíncrona dependendo do caso.
- Substituir o padrão verboso
new Promise((resolve) => resolve(func()))por uma chamada direta e legível. - Início de uma cadeia de
.then(), quando o primeiro passo já pode falhar de forma síncrona (ex: validar parâmetros antes de uma chamada de rede).
Diferença para Promise.resolve()
Promise.resolve(func()) primeiro executa func() — e se essa chamada lançar, o erro nunca chega a virar argumento de Promise.resolve(). Já Promise.try(func) executa a função dentro de um contexto que já sabe capturar exceções síncronas, transformando-as em rejeição. É a mesma diferença que existe entre chamar uma função direto dentro de um try/catch e chamá-la dentro do executor de new Promise().
Compatibilidade
Promise.try() atingiu o status Baseline "newly available" no início de 2025, com suporte no Chrome, Firefox e Safari, além do Node.js recente. Por ser uma adição nova, vale confirmar o suporte antes de usar em produção caso o projeto precise rodar em navegadores mais antigos, ou usar um polyfill nesse caso.
Conclusão
Promise.try() fecha uma lacuna que existia desde os primeiros dias das Promises: transformar qualquer chamada de função — síncrona, assíncrona, que lança erro ou que retorna Promise — em um único fluxo previsível, sem precisar recorrer ao construtor verboso de new Promise() só para capturar exceções síncronas.
0 Comentário
Deixe seu Comentário!