Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs Menu

Use Promesas con JavaScript asíncrono

El controlador Node.js utiliza la API asíncrona de JavaScript para comunicarse con tu clúster de MongoDB.

JavaScript asíncrono te permite ejecutar operaciones sin tener que esperar a que el hilo de procesamiento esté libre. Esto ayuda a evitar que tu aplicación se vuelva inoperante al ejecutar operaciones de larga duración. Para obtener más información sobre JavaScript asíncrono, consulte la documentación web de MDN sobre JavaScript asíncrono.

Esta sección describe Promises que puedes usar con el driver de Node.js para acceder a los resultados de tus llamadas de métodos en tu clúster de MongoDB.

Una Promesa (Promise) es un objeto retornado por la llamada de un método asíncrono que te permite acceder a información sobre el eventual éxito o fracaso de la operación que envuelve. The Promise está en estado de Pendiente si la operación aún se está ejecutando, Completada si la operación se completó con éxito, y Rechazada si la operación arrojó una excepción. Para obtener más información sobre Promises y la terminología relacionada, consulta la documentación sobre Promises.en MDN.

La mayoría de los métodos del driver que se comunican con tu clúster de MongoDB, como findOneAndUpdate() y countDocuments(), devuelve objetos Promise y ya contienen la lógica para gestionar el éxito o el fracaso de la operación.

Puedes definir tu propia lógica que se ejecuta una vez que el Promise alcanza el estado Cumplido o Rechazado añadiendo el método then(). El primer parámetro de then() es el método que se llama cuando la Promise alcanza el estado Cumplido y el segundo parámetro opcional es el método que se llama cuando alcanza el estado Rechazado. El método then() devuelve una Promise a la que puedes añadir más métodos then().

Cuando añades uno o más métodos then() a una Promise, cada llamada pasa su resultado de ejecución a la siguiente. Este patrón se llama Promise chaining. El siguiente fragmento de código muestra un ejemplo de encadenamiento de Promise mediante la adición de un solo método then().

collection
.updateOne({ name: "Mount McKinley" }, { $set: { meters: 6190 } })
.then(
res => console.log(`Updated ${res.result.n} documents`),
err => console.error(`Something went wrong: ${err}`),
);

Para gestionar únicamente las transiciones de Promesa al estado Rechazado, utiliza el método catch() en lugar de pasar un primer parámetro null a then(). El método catch() acepta una sola función de retorno que se ejecuta cuando la Promesa transita al estado Rechazado.

El método catch() se suele añadir al final de una cadena de Promise para gestionar cualquier excepción lanzada. El siguiente snippet de código demuestra cómo agregar un método catch() al final de una cadena de Promesas.

deleteOne({ name: "Mount Doom" })
.then(result => {
if (result.deletedCount !== 1) {
throw "Could not find Mount Doom!";
}
return new Promise((resolve, reject) => {
...
});
})
.then(result => console.log(`Vanquished ${result.quantity} Nazgul`))
.catch(err => console.error(`Fatal error occurred: ${err}`));

Nota

Ciertos métodos del driver, como find(), devuelven un Cursor en lugar de una Promise. Para determinar qué tipo devuelve cada método, consulta la documentación de la API de Node.js.

Si estás utilizando funciones async, puedes utilizar el operador await sobre una Promise para pausar la ejecución hasta que la Promise alcance el estado de Cumplida o Rechazada y retorne. Dado que el operador await espera a que se resuelva la Promise, puedes usarlo en lugar de la vinculación de Promises para ejecutar tu lógica secuencialmente. El siguiente fragmento de código utiliza await para ejecutar la misma lógica que el primer ejemplo de encadenamiento de Promise.

async function run() {
...
try {
res = await myColl.updateOne(
{ name: "Mount McKinley" },
{ $set: { meters: 6190 } },
);
console.log(`Updated ${res.result.n} documents`);
} catch (err) {
console.error(`Something went wrong: ${err}`);
}
}

Para obtener más información, consulta la documentación de MDN sobre await.

Un error común al usar async métodos es olvidar usar el await operador en Promises para obtener el valor del resultado en lugar del objeto Promise. Considera el siguiente ejemplo en el que iteramos sobre un cursor usando hasNext(), que devuelve una Promise que se resuelve en un valor booleano que indica si existen más resultados, y usando next(), que devuelve una Promise que se resuelve en la siguiente entrada a la que apunta el cursor.

async function run() {
...
// WARNING: this snippet may cause an infinite loop
const cursor = myColl.find();
while (cursor.hasNext()) {
console.log(cursor.next());
}
}

Dado que la llamada a hasNext() devuelve un Promise, la instrucción condicional devuelve true independientemente del valor al que se resuelva.

Si modificamos el código para await la llamada a next() solo, como se muestra en el siguiente snippet de código, arroja el siguiente error: MongoError: Cursor is closed.

async function run() {
...
// WARNING: this snippet throws a MongoError
const cursor = myColl.find();
while (cursor.hasNext()) {
console.log(await cursor.next());
}
}

Mientras que hasNext() no se llama hasta después de que se devuelve el resultado de next(), la llamada a hasNext() devuelve una Promise que se evalúa como true en lugar del valor al que se resuelve, similar al ejemplo anterior. El código intenta llamar a next() en un Cursor que ya ha devuelto sus resultados y se ha cerrado como resultado.

Si alteramos el código para solo await la llamada a hasNext() como se muestra en el siguiente ejemplo, la consola imprime objetos Promise en lugar de objetos document.

async function run() {
...
// WARNING: this snippet prints Promises instead of the objects they resolve to
const cursor = myColl.find();
while (await cursor.hasNext()) {
console.log(cursor.next());
}
}

Utiliza await antes de ambas llamadas a los métodos hasNext() y next() para asegurarte de que estás operando sobre los valores de retorno correctos, como se demuestra en el siguiente código:

async function run() {
...
const cursor = myColl.find();
while (await cursor.hasNext()) {
console.log(await cursor.next());
}
}