7 ‐ ¿Qué es una promesa en JS? - Jabes-Gonzalez/Checkpoint-8 GitHub Wiki

Una promesa es un objeto especial que actúa como contenedor para un valor que puede no estar disponible aún, pero que se resolverá en el futuro. Permite manejar operaciones asíncronas de manera más elegante que los callbacks tradicionales.

Estructura básica:
const miPromesa = new Promise((resolve, reject) => {
  // Lógica asíncrona
  if (operacionExitosa) {
    resolve(valor); // Éxito
  } else {
    reject(error); // Fracaso
  }
});

Estados de una Promesa

  • Pending (pendiente): Estado inicial, la operación está en proceso.
  • Fulfilled (cumplida): La operación terminó exitosamente y la promesa tiene un valor.
  • Rejected (rechazada): La operación falló y la promesa tiene una razón de rechazo. image

Creación de Promesas

Constructor básico
const promesa = new Promise((resolve, reject) => {
  setTimeout(() => {
    const exito = Math.random() > 0.5;
    exito ? resolve("¡Éxito!") : reject("Error");
  }, 1000);
});
Ejemplo práctico: Carga de scripts
function cargarScript(src) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = () => reject(new Error(`Error al cargar ${src}`));
    document.head.append(script);
  });
}

Consumo de Promesas

Métodos principales

image

Ejemplo:
cargarScript('mi-script.js')
  .then(src => console.log(`${src} cargado`))
  .catch(err => console.error(err))
  .finally(() => console.log('Proceso finalizado'));

Encadenamiento de Promesas

Las promesas pueden encadenarse para ejecutar operaciones secuenciales:

cargarScript('script1.js')
  .then(() => cargarScript('script2.js'))
  .then(() => cargarScript('script3.js'))
  .catch(err => console.error(err));
Manejo de errores en cadena:
cargarDatos()
  .then(procesar)
  .then(mostrar)
  .catch(err => {
    console.error('Error en la cadena:', err);
    return valorPorDefecto;
  });

Métodos Estáticos de Promise

image

Ejemplo con Promise.all():
const promesas = [
  fetch('/api/datos1'),
  fetch('/api/datos2'),
  fetch('/api/datos3')
];

Promise.all(promesas)
  .then(respuestas => {
    // Todas las respuestas exitosas
  })
  .catch(err => {
    // Manejo de primer error
  });

Ventajas sobre Callbacks Tradicionales

image

Ejemplos Avanzados

Convertir callback a promesa
function leerArchivo(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}
Uso con async/await (ES2017)
async function procesoAsync() {
  try {
    const dato1 = await obtenerDato1();
    const dato2 = await obtenerDato2(dato1);
    return procesar(dato2);
  } catch (error) {
    manejarError(error);
  }
}

Errores Comunes y Buenas Prácticas

Errores frecuentes:
  • Olvidar el return en .then()
  • No manejar errores con .catch()
  • Crear promesas innecesarias ("Promise constructor antipattern")
Buenas prácticas:
  • Siempre retornar promesas en cadenas
  • Usar Promise.all() para operaciones paralelas
  • Preferir async/await para código más legible
  • Siempre manejar errores con .catch() o try/catch en async/await.
  • Evitar crear promesas innecesarias (no envolver promesas existentes).

Las promesas revolucionaron el manejo de operaciones asíncronas en JavaScript, ofreciendo:

  • Mejor legibilidad con encadenamiento claro
  • Manejo centralizado de errores
  • Compatibilidad con operaciones paralelas y secuenciales
  • Base para características modernas como async/await Al dominar las promesas, los desarrolladores pueden escribir código asíncrono más mantenible y robusto, preparando el terreno para técnicas avanzadas de programación asíncrona.

Encadenamiento y Flujo de Promesas

Las promesas permiten encadenar operaciones asíncronas secuenciales usando .then(). Cada .then() devuelve una nueva promesa, lo que permite construir flujos complejos y controlados.

const miPromesa = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Primer paso"), 500);
});

miPromesa
  .then(resultado => {
    console.log(resultado); // "Primer paso"
    return "Segundo paso";
  })
  .then(segundo => {
    console.log(segundo); // "Segundo paso"
    return "Tercer paso";
  })
  .then(console.log) // "Tercer paso"
  .catch(console.error)
  .finally(() => console.log("Cadena completada"));

Cada .then() recibe el resultado del anterior. Si ocurre un error, la cadena salta al .catch() final.

Manejo de Errores y Garantías de las Promesas

  • Las promesas capturan errores tanto de operaciones asíncronas como de excepciones lanzadas en los callbacks.
  • Los errores pueden manejarse centralizadamente con .catch(), lo que evita la "pirámide de la perdición" de los callbacks anidados.
  • Es posible continuar la cadena después de un .catch():
new Promise((resolve, reject) => {
  resolve();
})
.then(() => {
  throw new Error("Algo falló");
})
.catch(() => {
  console.log("Manejo del error");
})
.then(() => {
  console.log("Continúa la cadena");
});

Esto imprime: Manejo del error / Continúa la cadena.

Métodos Estáticos Avanzados

image

Ejemplo con Promise.all():
Promise.all([
  fetch('/api/uno'),
  fetch('/api/dos')
])
.then(([res1, res2]) => Promise.all([res1.json(), res2.json()]))
.then(([json1, json2]) => {
  console.log(json1, json2);
})
.catch(console.error);

Ambas peticiones deben resolverse para continuar.

Patrones Avanzados y Consejos Prácticos

  • Encadenar Promesas Dinámicamente: Puedes construir cadenas de promesas en bucles o con arrays usando .reduce() para operaciones secuenciales.
  • Evitar el “Promise constructor antipattern”: No envuelvas promesas dentro de nuevas promesas innecesariamente.
  • Múltiples .then() sobre la misma promesa: Cada uno se ejecuta en orden de registro, todos reciben el mismo valor resuelto.
  • Transformar funciones de callback a promesa: Envolver APIs antiguas con el constructor Promise para modernizar el código.

Ejemplo Avanzado: Promesas Encadenadas y Manejo de Errores

function obtenerNumero() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const num = Math.floor(Math.random() * 10);
      num > 5 ? resolve(num) : reject('Número muy bajo');
    }, 500);
  });
}

obtenerNumero()
  .then(num => {
    console.log('Número:', num);
    return num * 2;
  })
  .then(doble => {
    console.log('Doble:', doble);
    return Promise.reject('Error simulado');
  })
  .catch(error => {
    console.error('Error capturado:', error);
    return 0;
  })
  .then(final => {
    console.log('Valor final:', final); // 0
  });

Demuestra flujo, manejo de errores y continuación tras un catch.

Recursos y Consejos de Expertos

  • Aprovecha los métodos estáticos (all, allSettled, race, any) para controlar flujos complejos.
  • Usa .finally() para limpiar recursos o actualizar la UI, sin importar el resultado.
  • Encadena siempre los retornos en .then() para evitar perder el flujo de datos y errores.
  • Consulta guías avanzadas para patrones profesionales y casos de uso reales.