¿Promise.all nativo de Node.js se procesa en paralelo o secuencialmente?
Me gustaría aclarar este punto, ya que la documentación no es demasiado clara al respecto;
P1: ¿Se Promise.all(iterable)
procesan todas las promesas de forma secuencial o en paralelo? O, más específicamente, ¿es el equivalente a ejecutar promesas encadenadas como
p1.then(p2).then(p3).then(p4).then(p5)....
¿O es algún otro tipo de algoritmo en el que todos p1
,,,,,, p2
etc. se llaman al mismo tiempo (en paralelo) y los resultados se devuelven tan pronto como todos se resuelven (o uno rechaza) p3
?p4
p5
P2: Si Promise.all
se ejecuta en paralelo, ¿existe una manera conveniente de ejecutar un iterable secuencialmente?
Nota : No quiero usar Q ni Bluebird, sino todas las especificaciones nativas de ES6.
¿ Está
Promise.all(iterable)
cumpliendo todas las promesas?
No, las promesas no pueden "ejecutarse". Comienzan su tarea cuando se crean (representan sólo los resultados) y usted ejecuta todo en paralelo incluso antes de pasarlos a Promise.all
.
Promise.all
sólo espera múltiples promesas. No importa en qué orden se resuelven o si los cálculos se ejecutan en paralelo.
¿Existe una forma conveniente de ejecutar un iterable secuencialmente?
Si ya tienes tus promesas, no puedes hacer mucho más Promise.all([p1, p2, p3, …])
(lo cual no tiene noción de secuencia). Pero si tiene un iterable de funciones asincrónicas, puede ejecutarlas secuencialmente. Básicamente necesitas llegar desde
[fn1, fn2, fn3, …]
a
fn1().then(fn2).then(fn3).then(…)
y la solución para hacerlo es usar Array::reduce
:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
En paralelo
await Promise.all(items.map(async (item) => {
await fetchItem(item)
}))
Ventajas: Más rápido. Todas las iteraciones se iniciarán incluso si una falla más adelante. Sin embargo, "fallará rápidamente" . Utilice Promise.allSettled
, para completar todas las iteraciones en paralelo, incluso si algunas arrojan. Técnicamente, se trata de invocaciones simultáneas, no en paralelo.
En secuencia
for (const item of items) {
await fetchItem(item)
}
Ventajas: las variables del bucle se pueden compartir en cada iteración. Se comporta como código síncrono imperativo normal.
NodeJS no ejecuta promesas en paralelo, las ejecuta simultáneamente ya que es una arquitectura de bucle de eventos de un solo subproceso. Existe la posibilidad de ejecutar cosas en paralelo creando un nuevo proceso hijo para aprovechar la CPU de múltiples núcleos.
Paralelo vs concurrente
De hecho, lo que Promise.all
hace es apilar la función de promesas en la cola apropiada (ver arquitectura de bucle de eventos) ejecutarlas simultáneamente (llamar a P1, P2,...) luego esperar cada resultado y luego resolver Promise.all con todas las promesas. resultados. Promise.all fallará con la primera promesa que falle, a menos que usted tenga que gestionar el rechazo usted mismo.
Hay una gran diferencia entre paralelo y concurrente, el primero ejecutará un cálculo diferente en un proceso separado exactamente al mismo tiempo y progresarán a su ritmo, mientras que el otro ejecutará el cálculo diferente uno tras otro sin esperar. el cómputo anterior para terminar y progresar al mismo tiempo sin depender unos de otros.
Finalmente, para responder a su pregunta, Promise.all
no se ejecutará ni en paralelo ni de forma secuencial sino de forma concurrente.