Promise.allSettled


Na 71.ª reunião do Ecma TC39, serão considerados o projeto e a implementação de referência do Promise.allSettled , o terceiro dos quatro principais combinadores de promessas.


Autores : Jason Williams (BBC), Robert Pumley (Bloomberg), Matthias Binens (Google)
Campeão : Matthias Binens (Google)
Etapa : 3


Para os fãs de podcasts, duplicados no YouTube .


Introdução e Motivação


Existem quatro principais combinadores no mundo das promessas:


  • Promise.all . ES2015. Fecha na primeira promessa rejeitada / rejeitada.
  • Promise.race . ES2015. Fecha na primeira promessa de alguma forma resolvida / estabelecida.
  • Promise.any . Etapa 1. Fecha na primeira promessa satisfeita / cumprida.
  • Promise.allSettled . Etapa 3 → Etapa 4. Não fecha.

Todos eles são amplamente representados em bibliotecas de usuários comuns, cada um deles é útil por si só e adequado em várias situações.


A principal aplicação desse combinador ocorre quando você deseja executar uma ação imediatamente após a conclusão de muitos pedidos, independentemente de terem terminado com êxito ou falha. O restante dos combinadores de promessas são fechados ( curto-circuito ), descartando os resultados dos valores de entrada que perderam a corrida por um determinado estado do sistema. Promise.allSettled é único, pois sempre espera todos por quem é responsável.


Promise.allSettled retorna uma promessa, que é executada com o retorno de uma matriz de instantâneos dos estados das promessas, mas somente após absolutamente todas as promessas originais serem resolvidas.


De onde vem o nome allSettled?


Dizemos que uma promessa é liquidada ( liquidada ) se não for suspensa pendente , ou seja, quando ele está satisfeito ou rejeitado - uma das duas coisas. Para entender a terminologia, dê uma olhada no antigo documento States and Fates .


E também, esse nome, allSettled , é amplamente usado em bibliotecas existentes que implementam essa funcionalidade. A lista estará abaixo.


Exemplos


Imagine que você precisa repetir uma série de promessas e retornar um novo valor com um status conhecido (que ocorre em qualquer um dos dois ramos possíveis da lógica).


 function reflect(promise) { return promise.then( (v) => { return { status: 'fulfilled', value: v }; }, (error) => { return { status: 'rejected', reason: error }; } ); } const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.all(promises.map(reflect)); const successfulPromises = results.filter(p => p.status === 'fulfilled'); 

A API proposta permite que o desenvolvedor processe essas opções, sem a necessidade de criar a função reflect independentemente ou armazenar os resultados em variáveis ​​temporárias. A nova API fica assim:


 const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.allSettled(promises); const successfulPromises = results.filter(p => p.status === 'fulfilled'); 

Se, por algum motivo, precisamos de promessas rejeitadas, provavelmente precisamos coletar os motivos do que aconteceu. allSettled torna isso tão fácil.


 const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.allSettled(promises); const errors = results .filter(p => p.status === 'rejected') .map(p => p.reason); 

Exemplos reais


Muito comum é o desejo de saber que todas as solicitações foram concluídas, independentemente do status de cada uma delas. Isso é importante quando você deseja fazer melhorias graduais no futuro. Nem sempre precisamos obter uma resposta da API.


 const urls = [ /* ... */ ]; const requests = urls.map(x => fetch(x)); // , -    ,  - - . //        ,   . try { await Promise.all(requests); console.log('  ,    .'); } catch { console.log('-    ,     . .'); } 

Usando Promise.allSettled você pode escrever algo que esteja mais de acordo com nossas expectativas.


 //   ,     API  . Promise.allSettled(requests).finally(() => { console.log('  :    ,   '); removeLoadingIndicator(); }); 

Implementações personalizadas



Em outros idiomas


Funcionalidade semelhante existe em outros idiomas, sob nomes diferentes. Como não há mecanismo universal que seja imediatamente compatível com muitos idiomas, este documento segue o exemplo dos nomes das bibliotecas listadas acima. Veja como fica em outros idiomas:


  • Ferrugem - futures::join ;
  • Task.WhenAll . Você pode usar try / catch ou TaskContinuationOptions.OnlyOnFaulted ;
  • Python - asyncio.wait com a opção ALL_COMPLETED
  • Java - CompletableFuture.allOf

Materiais para estudos adicionais



Ata das reuniões do TC39



Especificação



Implementações


Source: https://habr.com/ru/post/pt459970/


All Articles