Promise.all (). Then () resolve?

95

Usando o Node 4.x. Quando você tem um Promise.all(promises).then()qual é a maneira correta de resolver os dados e passá-los para o próximo .then()?

Eu quero fazer algo assim:

Promise.all(promises).then(function(data){
  // Do something with the data here
}).then(function(data){
  // Do more stuff here
});

Mas não tenho certeza de como enviar os dados para o segundo .then(). Não posso usar resolve(...)no primeiro .then(). Eu descobri que posso fazer isso:

return Promise.all(promises).then(function(data){
  // Do something with the data here
  return data;
}).then(function(data){
  // Do more stuff here
});

Mas essa não parece a maneira correta de fazer isso ... Qual é a abordagem certa para isso?

Jake Wilson
fonte

Respostas:

142

Mas essa não parece ser a maneira correta de fazer isso.

Essa é realmente a maneira correta de fazer isso (ou pelo menos uma maneira adequada de fazê-lo). Esse é um aspecto fundamental das promessas, elas são um pipeline e os dados podem ser manipulados pelos vários manipuladores no pipeline.

Exemplo:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("First handler", data);
    return data.map(entry => entry * 10);
  })
  .then(data => {
    console.log("Second handler", data);
  });

( catchmanipulador omitido por questões de brevidade. No código de produção, sempre propague a promessa ou lide com a rejeição.)

O resultado que vemos é:

Primeiro manipulador [1,2]
Segundo manipulador [10,20]

... porque o primeiro manipulador obtém a resolução das duas promessas ( 1e 2) como uma matriz e, em seguida, cria uma nova matriz com cada uma delas multiplicada por 10 e a retorna. O segundo manipulador obtém o que o primeiro manipulador retornou.

Se o trabalho adicional que você está fazendo for síncrono, você também pode colocá-lo no primeiro manipulador:

Exemplo:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("Initial data", data);
    data = data.map(entry => entry * 10);
    console.log("Updated data", data);
    return data;
  });

... mas se for assíncrono, você não vai querer fazer isso, pois acaba sendo aninhado, e o aninhamento pode rapidamente sair do controle.

TJ Crowder
fonte
1
Interessante. Obrigado. Então, não é possível rejectum valor após a Promisefunção inicial ? Ou um erro em qualquer lugar da cadeia o levará ao .catch()? Se for esse o caso, qual é o sentido de rejectem primeiro lugar? Por que não apenas lançar o erro? Obrigado mais uma vez,
Jake Wilson
6
@JakeWilson: Essas são perguntas diferentes. Mas você está confundindo duas coisas distintas: criar e cumprir a promessa e lidar com a promessa. Ao criar e cumprir a promessa, você usa resolvee reject. Ao manipular , se o processamento falhar, você de fato lança uma exceção para acionar o caminho da falha. E sim, você também pode lançar uma exceção do Promiseretorno de chamada original (em vez de usar reject), mas nem todas as falhas são exceções.
TJ Crowder
1

Hoje o NodeJS suporta uma nova async/awaitsintaxe. Esta é uma sintaxe fácil e torna a vida muito mais fácil

async function process(promises) { // must be an async function
    let x = await Promise.all(promises);  // now x will be an array
    x = x.map( tmp => tmp * 10);              // proccessing the data.
}

const promises = [
   new Promise(resolve => setTimeout(resolve, 0, 1)),
   new Promise(resolve => setTimeout(resolve, 0, 2))
];

process(promises)

Saber mais:

Aminadav Glickshtein
fonte
1
como posso passar parâmetros para cada promessa individual do processo? @ Aminadav Glickshtein
bhaRATh