loading...

[pt-BR] ES2020: Promise.allSettled

mesaquen profile image Mesaque Francisco ・2 min read

Uma nova adição que chega com o ES2020 é Promise.allSettled. Esse novo método chega para resolver um problema que deixava o código muito verboso na utilização de Promise.all.

Relembrando: Promises

Promise é um objeto usado para processamento assíncrono. Uma Promise representa um valor que pode estar disponível agora, no futuro ou nunca.

UmaPromise pode se encontrar em algum dos estados:

  • pending (pendente): Estado inicial, que não foi realizada nem rejeitada.
  • fulfilled (realizada): Sucesso na operação.
  • rejected (rejeitada): Falha na operação.
  • settled (estabelecida): Que foi realizada ou rejeitada.

Uma promessa pendente pode ter seu estado alterado para realizada com um valor ou ser rejeitada com um motivo (erro).

Relembrando: Promise.all

Promise.all é um método que recebe um objeto iterável contendo promises. Promise.all apenas retorna uma promise fulfilled caso todas as promises que foram passadas no objeto sejam também fulfilled caso contrário irá retornar uma promise com estado rejected.

Promise.allSettled

Promise.allSettled funciona de forma similar a Promise.all com a diferença que a promise resultante nunca é rejeitada caso uma das promises do objeto iterado seja rejeitada. Ao invés disso retorna um array com um objeto para cada promise contendo as propriedades:

  • status: fulfilled | rejected
  • value: valor da promise resolvida
  • reason: motivo da promise rejeitada

O novo método Promise.allSettled é bem útil quando você precisa executar uma operação que deve ser considerada completa independente de suas etapas falharem ou não. Como por exemplo, quando você quer fazer download de multiplos arquivos e ao final executar alguma outra ação.

Usando Promise.all você teria que adicionar um .catch para cada promise que será executada. Para evitar que o retorno de Promise.all seja uma promise rejeitada.

const download = async (url) => {/*...*/};
const handleFailedDownload = async url => {/*...*/};

const downloadAllFiles = async () => {
  const urls = [
    "http://example.com/exists.txt",
    "http://example.com/missing-file.txt"
  ];

  await Promise.all(urls.map(url => download(url).catch(handleFailedDownload)));
  doSomethingElse();
};

Usando Promise.allSettled você não precisa mais se preocupar com promises sendo rejeitadas em um loop. Porém ter

const download = async (url) => {/*...*/};

const downloadAllFiles = async () => {
  const urls = [
    'http://example.com/exists.txt',
    'http://example.com/missing-file.txt'
  ];

  await Promise.allSettled(urls.map(url => download(url));
  doSomethingElse();
};

Atenção com os valores retornados

Diferente de Promise.all onde em caso de sucesso, os valores são retornados diretamente no array de resultados. Em Promise.allSettled o array de resultados retorna contém um SettlementObject para cada promise passada no iterável inicial.

Abaixo você encontra uma representação da assinatura dos retornos de Promise.allSettled.

type SettlementObject<T> = FulFillmentObject<T> | RejectionObject<T>;

interface SettlementObject<T> {
  status: "fulfilled";
  value: T;
}

interface RejectionObject {
  status: "rejected";
  reason: unknown;
}

Exemplo de Promise.allSettled

const results = Promise.allSettled([
  Promise.resolve("OK"),
  Promise.reject("ERROR"),
  Promise.resolve("OK TOO")
]);

console.log(results);

/**
Expected output:
[
  { status: 'fulfilled', value: 'OK' },
  { status: 'rejected', reason: 'ERROR' },
  { status: 'fulfilled', value: 'OK TOO'},
]
*/

Discussion

pic
Editor guide