DMarlon Studio

Lección 13 · 13 de 20

Promise.all, allSettled y race · JavaScript

Lance varias tareas asíncronas a la vez en JavaScript y combine sus resultados con Promise.all, allSettled, race y any.

JavaScript · Promise.all, allSettled y race en DMarlon Studio: el código del ejemplo y su salida en la terminal

Cuando hay varias tareas asíncronas independientes, no hace falta esperarlas una a una. `Promise.all` las lanza a la vez y espera a todas: la página de producto tarda lo que el servicio más lento (60 ms), no la suma de los tres. Los resultados llegan en el orden del array, no en el orden en que terminaron: prices sale primero aunque fue el último.

Promise.all es «todo o nada»: en cuanto una promesa se rechaza, el conjunto se rechaza con ese error, sin esperar a las demás. Por eso payments failed llega al catch a los 10 ms.

`Promise.allSettled` nunca se rechaza: espera a todas y devuelve un informe de cada una, con status igual a fulfilled (y su value) o rejected (y su reason). Es lo adecuado cuando quiere saber qué ha fallado sin perder lo que sí ha funcionado, como al enviar avisos por correo y por SMS.

`Promise.race` se queda con la primera promesa que termine, bien o mal: sirve para elegir el servidor más rápido o para poner un tiempo límite. `Promise.any` se queda con la primera que se cumpla e ignora los fallos: aunque cache falla a los 5 ms, gana database. Cada servicio usa un retraso distinto para que el resultado sea siempre el mismo.

Código · main.js

// A fake service that answers (or fails) after a fixed delay in ms.function service(name, ms, ok = true) {  return new Promise((resolve, reject) =>    setTimeout(() => (ok ? resolve(`${name} ${ms}ms`) : reject(new Error(`${name} failed`))), ms)  );}async function main() {  // all: waits for every promise; results keep the order of the array.  const page = await Promise.all([service("prices", 60), service("stock", 20), service("reviews", 40)]);  console.log("all:", page.join(" | "));  // all rejects as soon as one of the promises rejects.  try {    await Promise.all([service("prices", 30), service("payments", 10, false)]);  } catch (err) {    console.log("all rejected:", err.message);  }  // allSettled: never rejects; it reports the outcome of each one.  const sent = await Promise.allSettled([service("email", 20), service("sms", 10, false)]);  for (const r of sent) console.log("allSettled:", r.status, "-", r.value ?? r.reason.message);  // race: the first promise to settle wins, fulfilled or rejected.  const fastest = await Promise.race([service("mirror-eu", 50), service("mirror-us", 15)]);  console.log("race winner:", fastest);  // any: the first one to fulfil wins; failures are ignored.  const firstOk = await Promise.any([service("cache", 5, false), service("database", 25)]);  console.log("any:", firstOk);}main();

Salida · node main.js

all: prices 60ms | stock 20ms | reviews 40ms
all rejected: payments failed
allSettled: fulfilled - email 20ms
allSettled: rejected - sms failed
race winner: mirror-us 15ms
any: database 25ms

Para recordar

  • Promise.all espera a todas y conserva el orden; un solo fallo lo rechaza.
  • Promise.allSettled informa del resultado de cada una y nunca se rechaza.
  • Promise.race devuelve la primera que termine, cumplida o rechazada.
  • Promise.any devuelve la primera que se cumpla.

Ejercicio

Escriba una función withTimeout(promise, ms) que use Promise.race con una promesa que se rechace a los ms milisegundos, y pruébela con service("prices", 60) y un límite de 30 ms.