Promise.all (). Luego () resolver?

95

Usando Node 4.x. Cuando tiene una, Promise.all(promises).then()¿cuál es la forma correcta de resolver los datos y pasarlos a la siguiente .then()?

Quiero hacer algo como esto:

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

Pero no estoy seguro de cómo llevar los datos al 2do .then(). No puedo usar resolve(...)en el primero .then(). Descubrí que puedo hacer esto:

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

Pero esa no parece la forma correcta de hacerlo ... ¿Cuál es el enfoque correcto para esto?

Jake Wilson
fuente

Respuestas:

142

Pero esa no parece la forma correcta de hacerlo ...

De hecho, esa es la forma correcta de hacerlo (o al menos una forma correcta de hacerlo). Este es un aspecto clave de las promesas, son una canalización y los datos pueden ser manipulados por los diversos controladores en la canalización.

Ejemplo:

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);
  });

(El catchcontrolador se omite por brevedad. En el código de producción, siempre propague la promesa o controle el rechazo).

El resultado que vemos de eso es:

Primer manipulador [1,2]
Segunda mano [10,20]

... porque el primer controlador obtiene la resolución de las dos promesas ( 1y 2) como una matriz, y luego crea una nueva matriz con cada una de ellas multiplicada por 10 y la devuelve. El segundo controlador obtiene lo que devolvió el primer controlador.

Si el trabajo adicional que está haciendo es sincrónico, también puede ponerlo en el primer controlador:

Ejemplo:

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;
  });

... pero si es asincrónico, no querrá hacer eso, ya que termina anidando, y la anidación puede salirse de control rápidamente.

TJ Crowder
fuente
1
Interesante. Gracias. Entonces, ¿no es posible obtener rejectun valor después de la Promisefunción inicial ? ¿O arrojar un error en cualquier parte de la cadena lo llevará al .catch()? Si ese es el caso, ¿cuál es el punto de rejecten primer lugar? ¿Por qué no lanzar un error? Gracias de nuevo,
Jake Wilson
6
@JakeWilson: Esas son preguntas diferentes. Pero está confundiendo dos cosas separadas: crear y establecer la promesa y manejar la promesa. Cuando crea y establece la promesa, usa resolvey reject. Cuando está manejando , si su procesamiento falla, de hecho lanza una excepción para activar la ruta de falla. Y sí, también puede lanzar una excepción de la Promisedevolución de llamada original (en lugar de usar reject), pero no todas las fallas son excepciones.
TJ Crowder
1

Hoy, NodeJS admite una nueva async/awaitsintaxis. Esta es una sintaxis fácil y hace la vida mucho más 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)

Aprende más:

Aminadav Glickshtein
fuente
1
¿Cómo puedo pasar parámetros a cada promesa individual del proceso? @ Aminadav Glickshtein
bhaRATh