| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Using_promises | [Back] [Original] |
Get to know MDN better
Esta pgina ha sido traducida del ingls por la comunidad. Aprende ms y nete a la comunidad de MDN Web Docs.
Una Promise (promesa en castellano) es un objeto que representa la terminacin o el fracaso de una operacin asncrona. Dado que la mayora de las personas consumen promises ya creadas, esta gua explicar primero cmo consumirlas, y luego cmo crearlas.
Esencialmente, una promesa es un objeto devuelto al cual se adjuntan funciones callback, en lugar de pasar callbacks a una funcin.
Considera la funcin crearArchivoAudioAsync(), la cual genera de manera asncrona un archivo de sonido de acuerdo a un archivo de configuracin, y dos funciones callback, una que es llamada si el archivo de audio es creado satisfactoriamente, y la otra que es llamada si ocurre un error. El cdigo podra verse de la siguiente forma:
function exitoCallback(resultado) {
console.log("Archivo de audio disponible en la URL " + resultado);
}
function falloCallback(error) {
console.log("Error generando archivo de audio " + error);
}
crearArchivoAudioAsync(audioConfig, exitoCallback, falloCallback);
... las funciones modernas devuelven un objeto promise al que puedes adjuntar funciones de retorno (callbacks). Si crearArchivoAudioAsync fuera escrita de manera tal que devuelva un objeto promise, usarla sera tan simple como esto:
crearArchivoAudioAsync(audioConfig).then(exitoCallback, falloCallback);
Lo cual es la versin corta de:
const promesa = crearArchivoAudioAsync(audioConfig);
promesa.then(exitoCallback, falloCallback);
Llamamos a esto una llamada a funcin asncrona. Esta convencin tiene varias ventajas. Exploraremos cada una de ellas.
A diferencia de las funciones callback pasadas al "viejo estilo", una promesa viene con algunas garantas:
then() incluso despus del xito o fracaso de la operacin asncrona sern llamadas como se mostr anteriormente.then() varias veces. Cada una de ellas es ejecutada una seguida de la otra, en el orden en el que fueron insertadas.Una de las grandes ventajas de usar promises es el encadenamiento, explicado a continuacin.
Una necesidad comn es el ejecutar dos o ms operaciones asncronas seguidas, donde cada operacin posterior se inicia cuando la operacin previa tiene xito, con el resultado del paso previo. Logramos esto creando una cadena de objetos promises.
Aqu est la magia: la funcin then() devuelve una promesa nueva, diferente de la original:
const promesa = hazAlgo();
const promesa2 = promesa.then(exitoCallback, falloCallback);
o
let promesa2 = hazAlgo().then(exitoCallback, falloCallback);
Esta segunda promesa (promesa2) representa no slo la terminacin de hazAlgo(), sino tambin de exitoCallback o falloCallback que pasaste, las cuales pueden ser otras funciones asncronas devolviendo una promesa. Cuando ese es el caso, cualquier funcin callback aadida a promesa2 se queda en cola detrs de la promesa devuelta por exitoCallback o falloCallback.
Bsicamente, cada promesa representa la terminacin de otro paso (asncrono on no) en la cadena.
En el pasado, hacer varias operaciones asncronas en fila conducira a la clsica pirmide de funciones callback:
hazAlgo(function(resultado) {
hazAlgoMas(resultado, function(nuevoResultado) {
hazLaTerceraCosa(nuevoResultado, function(resultadoFinal) {
console.log('Obtenido el resultado final: ' + resultadoFinal
}, falloCallback);
}, falloCallback);
}, falloCallback);
Con las funciones modernas, adjuntamos nuestras functiones callback a las promesas devueltas, formando una cadena de promesa:
hazAlgo()
.then(function (resultado) {
return hazAlgoMas(resultado);
})
.then(function (nuevoResultado) {
return hazLaTerceraCosa(nuevoResultado);
})
.then(function (resultadoFinal) {
console.log("Obtenido el resultado final: " + resultadoFinal);
})
.catch(falloCallback);
Los argumentos a then son opcionales, y catch(falloCallBack) es un atajo para then(null, falloCallBack). Es posible que veas esto expresado con funciones de flecha :
hazAlgo()
.then((resultado) => hazAlgoMas(resultado))
.then((nuevoResultado) => hazLaTerceraCosa(nuevoResultado))
.then((resultadoFinal) => {
console.log(`Obtenido el resultado final: ${resultadoFinal}`);
})
.catch(falloCallback);
Importante: Devuelve siempre resultados, de otra forma las funciones callback no se encadenarn, y los errores no sern capturados.
Es posible encadenar despus de un fallo - por ejemplo: un catch- lo que es til para lograr nuevas acciones incluso despus de una accin fallida en la cadena. Lea el siguiente ejemplo:
new Promise((resolver, rechazar) => {
console.log("Inicial");
resolver();
})
.then(() => {
throw new Error("Algo fall");
console.log("Haz esto");
})
.catch(() => {
console.log("Haz aquello");
})
.then(() => {
console.log("Haz esto sin que importe lo que sucedi antes");
});
Esto devolver el siguiente texto:
Inicial Haz aquello Haz esto sin que importe lo que sucedi antes
Note que el texto "Haz esto" no es escrito porque el error "Algo fall" caus un rechazo.
Tal vez recuerdes haber visto falloCallback tres veces en la pirmide en un ejemplo anterior, en comparacin con slo una vez al final de la cadena de promesas:
hazAlgo()
.then((resultado) => hazAlgoMas(valor))
.then((nuevoResultado) => hazLaTerceraCosa(nuevoResultado))
.then((resultadoFinal) =>
console.log(`Obtenido el resultado final: ${resultadoFinal}`),
)
.catch(falloCallback);
Bsicamente, una cadena de promesas se detiene si hay una excepcin, y recorre la cadena buscando manejadores de captura. Lo siguiente est mucho ms adaptado a la forma de trabajo del cdigo sncrono:
try {
let resultado = syncHazAlgo();
let nuevoResultado = syncHazAlgoMas(resultado);
let resultadoFinal = syncHazLaTerceraCosa(nuevoResultado);
console.log(`Obtenido el resultado final: ${resultadoFinal}`);
} catch (error) {
falloCallback(error);
}
Esta simetra con el cdigo sncrono culmina con la mejora sintctica async/await en ECMASCript 2017:
async function foo() {
try {
let resultado = await hazAlgo();
let nuevoResultado = await hazAlgoMas(resultado);
let resultadoFinal = await hazLaTerceraCosa(nuevoResultado);
console.log(`Obtenido el resultado final: ${resultadoFinal}`);
} catch (error) {
falloCallback(error);
}
}
Se construye sobre promesas, por ejemplo, hazAlgo() es la misma funcin que antes. Puedes leer ms sobre la sintaxis aqu.
Las promesas resuelven un fallo fundamental de la pirmide de funciones callback, capturando todos los errores, incluso excepciones lanzadas y errores de programacin. Esto es esencial para la composicin funcional de operaciones asncronas.
Cuando una promesa es rechazada, uno de los dos eventos se enva al mbito global (generalmente, ste es el window, o, si se utiliza en un trabajador web, es el Worker u otra interfaz basada en un trabajador). Los dos eventos son:
rejectionhandledSe enva cuando se rechaza una promesa, una vez que el rechazo ha sido manejado por la funcin reject del ejecutor.
unhandledrejectionSe enva cuando se rechaza una promesa pero no hay un controlador de rechazo disponible.
En ambos casos, el evento (del tipo PromiseRejectionEvent) tiene como miembros una propiedad promise que indica que la promesa fue rechazada, y una propiedad reason que proporciona el motivo por el cul se rechaza la promesa.
Esto hace posible ofrecer el manejo de errores de promesas, y tambin ayuda a depurarlos. Estos controladores son globales, por lo tanto, todos los errores sern manejados por stos independientemente de la fuente.
Un caso de especial utilidad: al escribir cdigo para Node.js, es comn que los mdulos que incluyas en tu proyecto no cuenten con un controlador de evento para promesas rechazadas. Estos se registran en la consola en tiempo de ejecucin de Node. Puedes capturarlos para analizarlos y manejarlos en tu cdigo - o solo evitar que abarroten tu salida - agregando un controlador para el evento unhandledrejection, como se muestra a continuacin:
window.addEventListener(
"unhandledrejection",
(event) => {
/* Podras comenzar agregando cdigo para examinar
la promesa especfica analizando event.promise
y la razn del rechazo, accediendo a event.reason */
event.preventDefault();
},
false,
);
Llamando al mtodo preventDefault() del evento, le dices a Javascript en tiempo de ejecucin que no realice su accin predeterminada cuando las promesas rechazadas no cuenten con manejadores. En el caso de Node, esa accin predeterminada usualmente registra el error en la consola.
Lo ideal, por supuesto, sera examinar las promesas rechazadas para asegurarte que ninguna de ellas tienen errores de cdigo reales antes de descartar esos eventos.
Una Promise puede ser creada desde cero usando su constructor. Esto debera ser slo necesario para envolver viejas APIs.
En un mundo ideal, todas las funciones asncronas devolveran promesas. Desafortunadamente, algunas APIs an esperan que se les pase callbacks con resultado fallido/exitoso a la forma antigua. El ejemplo ms obvio es la funcin setTimeout():
setTimeout(() => diAlgo("pasaron 10 segundos"), 10000);
Combinar callbacks del viejo estilo con promesas es problemtico. Si diAlgo falla o contiene un error de programacin, nada lo captura. La funcin setTimeout es culpable de esto.
Afortunadamente podemos envolverlas en una promesa. La mejor prctica es envolver las funciones problemticas en el nivel ms bajo posible, y despus nunca llamarlas de nuevo directamente:
const espera = (ms) => new Promise((resuelve) => setTimeout(resuelve, ms));
espera(10000)
.then(() => diAlgo("10 segundos"))
.catch(falloCallback);
Bsicamente, el constructor de la promesa toma una funcin ejecutora que nos permite resolver o rechazar manualmente una promesa. Dado que setTimeout no falla realmente, descartamos el rechazo en este caso.
Promise.resolve() y Promise.reject() son atajos para crear manualmente una promesa resuelta o rechazada respectivamente. Esto puede ser til a veces.
Promise.all() son Promise.race() son dos herramientas de composicin para ejecutar operaciones asncronas en paralelo.
Podemos comenzar operaciones en paralelo y esperar que finalicen todas ellas de la siguiente manera:
Promise.all([func1(), func2(), func3()]).then(
([resultado1, resultado2, resultado3]) => {
/* usa resultado1, resultado2 y resultado3 */
},
);
La composicin secuencial es posible usando Javascript inteligente:
[func1, func2, func3]
.reduce((p, f) => p.then(f), Promise.resolve())
.then((result3) => {
/* use result3 */
});
Bsicamente, reducimos un conjunto de funciones asncronas a una cadena de promesas equivalente a: Promise.resolve().then(func1).then(func2).then(func3);
Esto se puede convertir en una funcin de composicin reutilizable, que es comn en la programacin funcional:
const aplicarAsync = (acc, val) => acc.then(val);
const componerAsync =
(...funcs) =>
(x) =>
funcs.reduce(aplicarAsync, Promise.resolve(x));
La funcin componerAsync() aceptar cualquier nmero de funciones como argumentos, y devolver una nueva funcin que acepta un valor inicial que es pasado a travs del conducto de composicin. Esto es beneficioso porque cualquiera o todas las funciones pueden ser o asncronas o sncronas y se garantiza que sern ejecutadas en el orden correcto:
const transformData = componerAsync(func1, asyncFunc1, asyncFunc2, func2);
const resultado3 = transformData(data);
En ECMAScript 2017, la composicin secuencial puede ser realizada usando simplemente async/await:
let resultado;
for (const f of [func1, func2, func3]) {
resultado = await f(resultado);
}
Para evitar sorpresas, las funciones pasadas a then() nunca sern llamadas sincrnicamente, incluso con una promesa ya resuelta:
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
En lugar de ejecutarse inmediatamente, la funcin pasada es colocada en una cola de microtareas, lo que significa que se ejecuta ms tarde cuando la cola es vaciada al final del actual ciclo de eventos de JavaScript:
const espera = (ms) => new Promise((resuelve) => setTimeout(resuelve, ms));
espera().then(() => console.log(4));
Promise.resuelve()
.then(() => console.log(2))
.then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
Las cadenas de promesas simples se mantienen planas sin anidar, ya que el anidamiento puede ser el resultado de una composicin descuidada. Vea errores comunes.
El anidamiento es una estructura de control para limitar el alcance de las sentencias catch. Especficamente, un catch anidado slo captura fallos dentro de su contexto y por debajo, no captura errores que estn ms arriba en la cadena fuera del alcance del anidamiento. Cuando se usa correctamente, da mayor precisin en la recuperacin de errores:
hacerAlgoCritico()
.then((resultado) =>
hacerAlgoOpcional()
.then((resultadoOpcional) => hacerAlgoSuper(resultadoOpcional))
.catch((e) => {}),
) // Ignorar si hacerAlgoOpcional falla.
.then(() => masAsuntosCriticos())
.catch((e) => console.log("Accin crtica fallida: " + e.message));
Nota que aqu los pasos opcionales estn anidados, por la precaria colocacin de lo externo (y) alrededor de ellos.
La declaracin interna catch solo detecta errores de hacerAlgoOpcional() y hacerAlgoSuper(), despus de lo cul el cdigo se reanuda con masAsuntosCriticos(). Es importante destacar que si hacerAlgoCritico() falla, el error es capturado nicamente por el catch final.
Aqu hay algunos errores comunes que deben tenerse en cuenta al componer cadenas de promesas. Varios de estos errores se manifiestan en el siguiente ejemplo:
// Mal ejemplo!
hacerlAlgo()
.then(function (resultado) {
hacerOtraCosa(resultado) // Olvida devolver una promesa desde el interior de la cadena + anidamiento innecesario
.then((nuevoResultado) => hacerUnaTerceraCosa(nuevoResultado));
})
.then(() => hacerUnaCuartaCosa());
// Olvida terminar la cadena con un catch!
El primer error es no encadenar las acciones adecuadamente. Esto sucede cuando creamos una promesa y olvidamos devolverla. Como consecuencia, la cadena se rompe, o mejor dicho, tenemos dos cadenas independientes que compiten. Esto significa que hacerUnaCuartaCosa() no esperar a que finalicen hacerOtraCosa() o hacerUnaTerceraCosa(), y se ejecutar paralelamente a ellas. Las cadenas separadas tambin tienen un manejador de errores separado, lo que provoca errores no detectados.
El segundo error es el anidamiento innecesario, que da lugar al primer error. La anidacin tambin limita el alcance de los manejadores de errores internos, que - si no son deseados - pueden llevar a errores no detectados. Una variante de esto es el constructor anti-patrn de promesas, el cul combina el anidamiento con el uso redundante del constructor de promesa para envolver el cdigo que ya usa promesas.
El tercer error es olvidar cerrar las cadenas con catch. Las cadenas de promesas no terminadas conducen a errores no capturados en la mayora de los navegadores.
Una buena regla es devolver o terminar siempre las cadenas de promesas, y tan pronto como obtenga una nueva promesa, devolverla de inmediato, para aplanar las cosas:
hacerAlgo()
.then(function (resultado) {
return hacerOtraCosa(resultado);
})
.then((nuevoResultado) => hacerUnaTerceraCosa(nuevoResultado))
.then(() => hacerUnaCuartaCosa())
.catch((error) => console.log(error));
Nota que () => x es un atajo para () => { return x; }.
Ahora tenemos una cadena determinstica simple con un manejador de error adecuado.
El uso de async / await aborda la mayora, si no todos estos problemas, la desventaja es que el error ms comn con esa sintaxis es olvidar la palabra clave await.
Promise.then()This page was last modified on 20 jun 2025 by MDN contributors.
Your blueprint for a better internet.
Portions of this content are 19982026 by individual mozilla.org contributors. Content available under a Creative Commons license.
| Web Proxy Viewer | New URL | Original Page |