JavaScript - Combinadores de Promises
Tags: ptbr, webdev, javascript, node
Published: 2019-06-15 00:30:56

## Ententendo a API de Promises e suas novidades

Desde a introdução de **Promises** no ES2015, o JavaScript suportou exatamente dois combinadores: os métodos estáticos `Promise.all` e `Promise.race`.

Duas novas propostas estão atualmente passando pelo processo de padronização: `Promise.allSettled` e `Promise.any`. Com essas adições, haverá um total de **quatro combinadores de Promises** em JavaScript, cada um permitindo diferentes casos de uso.

Aqui está uma visão geral dos quatro combinadores:

- **‌Promise.allSettled**: não há curto-circuito, [em proposta](https://github.com/tc39/proposal-promise-allSettled)
- **Promise.all**: curto-circuito quando um valor de entrada é rejeitado, adicionado no ES2015 ✅
- **Promise.race**: curto-circuito quando algum valor de entrada for decidido (rejeitado ou resolvido), adicionado no ES2015 ✅
- **Promise.any**: curto-circuito quando um valor de entrada for resolvido, [em proposta](https://github.com/tc39/proposal-promise-any)

Vamos dar uma olhada em um exemplo de caso de uso para cada combinador.

# Promise.all

![](https://thepracticaldev.s3.amazonaws.com/i/u9uj9tg5cx5of4l4tdmu.png)
_Veja o suporte em https://v8.dev/features/support_

`Promise.all` permite que você saiba quando todas as promessas de entrada foram cumpridas ou quando uma delas foi rejeitada.

Imagine que o usuário clica em um botão e deseja carregar algumas folhas de estilo para que você possa renderizar uma interface de usuário completamente nova. Este programa inicia uma solicitação HTTP para cada folha de estilo em paralelo:

```js
const promises = [
  fetch('/component-a.css'),
  fetch('/component-b.css'),
  fetch('/component-c.css'),
];
try {
  const styleResponses = await Promise.all(promises);
  enableStyles(styleResponses);
  renderNewUi();
} catch (reason) {
  displayError(reason);
}
```

Você só deseja começar a renderizar a nova interface de usuário depois que todas as solicitações forem bem-sucedidas. Se algo der errado, você deseja exibir uma mensagem de erro o mais rápido possível, sem esperar que outro trabalho acabe.

Nesse caso, você poderia usar `Promise.all`: você quer saber quando todas as promessas são cumpridas ou assim que uma delas é rejeitada.

# Promise.race

![](https://thepracticaldev.s3.amazonaws.com/i/ffs8af2416sy67nneuqx.png)
_Veja o suporte em https://v8.dev/features/support_

`Promise.race` é útil se você deseja executar várias promessas e também:

1. fazer algo com o primeiro resultado bem-sucedido que chegar (no caso de uma das promessas ser cumprida), ou
2. faça algo assim que uma das promessas for rejeitada.

Isto é, se uma das promessas for rejeitada, você quer preservar essa rejeição para tratar o caso de erro separadamente. O exemplo a seguir faz exatamente isso:

```js
try {
  const result = await Promise.race([
    performHeavyComputation(),
    rejectAfterTimeout(2000),
  ]);
  renderResult(result);
} catch (error) {
  renderError(error);
}
```

Iniciamos uma tarefa computacionalmente pesada que pode levar muito tempo, mas corremos contra uma promessa que rejeita após 2 segundos. Dependendo da primeira promessa a ser cumprida ou rejeitada, renderizamos o resultado computado ou a mensagem de erro em dois caminhos de código separados.

# Promise.allSettled

![](https://miro.medium.com/max/2060/1*ZKLq7j_MpTrID5ht025pTA.png)
_Veja o suporte em https://v8.dev/features/support_

`Promise.allSettled` te dá um sinal quando todas as promessas de entrada são decididas, o que significa que elas são resolvidas ou rejeitadas. Isso é útil nos casos em que você não se importa com o estado das promessas, você só quer saber quando o trabalho está concluído, independentemente de ter sido bem-sucedido.

Por exemplo, você pode dar início a uma série de chamadas de API independentes e usa `Promise.allSettled` para garantir que todas sejam concluídas antes de fazer outra coisa, como remover um controle giratório de carregamento:

```js
const promises = [
  fetch('/api-call-1'),
  fetch('/api-call-2'),
  fetch('/api-call-3'),
];
// Imagine que algumas dessas requisições falhem e outras são bem-sucedidas

await Promise.allSettled(promises);

// Todas as chamadas de API foram finalizadas (falhas e sucessos)
removeLoadingIndicator();
```

# Promise.any

![](https://miro.medium.com/max/2024/1*1mF4tA93h53iLYeScGHM8g.png)
_Veja o suporte em https://v8.dev/features/support_

`Promise.any` te dá um sinal assim que uma das promessas se cumprem. Isso é semelhante a `Promise.race`, exceto que `any` não rejeita cedo quando uma das promessas é rejeitada.

```js
const promises = [
  fetch('/endpoint-a').then(() => 'a'),
  fetch('/endpoint-b').then(() => 'b'),
  fetch('/endpoint-c').then(() => 'c'),
];
try {
  const first = await Promise.any(promises);
  // Qualquer uma das promessas foi cumprida.
  // → e.g. 'b'
  console.log(first);
} catch (error) {
  // Todas as promessas foram rejeitadas.
  console.log(error);
}
```

Este exemplo de código verifica qual endpoint responde o mais rápido e faz o log dele. Somente se todos os pedidos falharem, acabaremos no bloco `catch`, onde poderemos lidar com os erros.

# Créditos ⭐️
- [Promise combinators](https://v8.dev/features/promise-combinators), escrito originalmente por [Mathias Bynens](https://twitter.com/mathias)