Toda vez que você precisa resolver ou rejeitar uma Promise a partir de um código que está fora do callback do construtor, acaba caindo no mesmo truque: declarar variáveis soltas e atribuí-las lá dentro. O método estático Promise.withResolvers() resolve esse incômodo devolvendo, de uma só vez, a Promise e as suas funções resolve e reject.
O jeito antigo
let resolve, reject;
const promessa = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
// Em algum outro lugar, mais tarde:
resolve('pronto!');
Funciona, mas é verboso: são três declarações só para conseguir "escapar" o resolve e o reject para fora do escopo do construtor.
Como funciona o withResolvers
O método devolve um objeto simples com três propriedades: a própria promise, e as funções resolve e reject já prontas para serem chamadas quando você quiser.
const { promise, resolve, reject } = Promise.withResolvers();
// Em algum outro lugar, mais tarde:
resolve('pronto!');
promise.then(valor => console.log(valor)); // "pronto!"
Com uma única linha e desestruturação você tem tudo o que antes exigia o bloco com let. Nada de variáveis soltas e sem valor inicial.
Exemplo prático: esperar um evento
Um caso clássico é transformar um evento único (como um clique) em algo que você possa await. Fica bem mais limpo:
function esperarClique(botao) {
const { promise, resolve } = Promise.withResolvers();
botao.addEventListener('click', resolve, { once: true });
return promise;
}
const evento = await esperarClique(document.querySelector('#confirmar'));
console.log('Usuário confirmou!', evento);
Exemplo prático: fila de tarefas
Quando o resolve precisa ser guardado para ser chamado por outra parte do sistema, o padrão brilha. Aqui, cada tarefa enfileirada vira uma Promise cujo controle fica com o processador:
const fila = [];
function enfileirar(tarefa) {
const { promise, resolve, reject } = Promise.withResolvers();
fila.push({ tarefa, resolve, reject });
return promise;
}
async function processar() {
while (fila.length) {
const { tarefa, resolve, reject } = fila.shift();
try {
resolve(await tarefa());
} catch (erro) {
reject(erro);
}
}
}
Quem chama enfileirar() recebe uma Promise e simplesmente aguarda; o processar() decide quando cada uma é resolvida ou rejeitada.
Quando usar
- Converter APIs baseadas em eventos ou callbacks em Promises que dá para
await. - Filas de tarefas, onde o
resolveé chamado por um processador externo. - Streams e sockets, para sinalizar de fora quando um dado chegou.
- Testes, quando você precisa controlar manualmente o momento em que uma Promise resolve.
Detalhes de comportamento
As funções resolve e reject retornadas são exatamente as mesmas que o construtor entregaria: chamadas depois que a Promise já foi resolvida ou rejeitada simplesmente não têm efeito. Além disso, o objeto retornado é um objeto comum, então a desestruturação é a forma mais prática de usá-lo, mas você também pode guardá-lo inteiro em uma variável se preferir.
Compatibilidade
O Promise.withResolvers() faz parte do ECMAScript 2024 e já atingiu o status Baseline, com suporte nos navegadores modernos e no Node.js recente. Ainda assim, vale conferir antes de usar em produção se o projeto precisar suportar ambientes mais antigos.
Conclusão
O Promise.withResolvers() elimina um padrão repetitivo e um pouco desajeitado que acompanhava o JavaScript há anos, deixando explícito e enxuto o caso em que o controle de resolução da Promise precisa viver fora do seu construtor.
0 Comentário
Deixe seu Comentário!