sql >> Base de Datos >  >> NoSQL >> MongoDB

Mongoose pasa datos fuera de withTransaction helper

Parece que hay cierta confusión aquí sobre cómo usar Promesas correctamente, en varios niveles.

Devolución de llamada y Promesa se utilizan incorrectamente

Si se supone que la función debe aceptar una devolución de llamada, no devuelva una Promesa. Si se supone que la función devolverá una Promesa, use la devolución de llamada dada por la Promesa:

const transactionSession = await mongoose.startSession()
await transactionSession.withTransaction( (tSession) => {
    return new Promise( (resolve, reject) => {
        //using Node-style callback
        doSomethingAsync( (err, testData) => {
            if(err) {
                reject(err);
            } else {
                resolve(testData); //this is the equivalent of cb(null, "Any test data")
            }
        });
    })

Veamos esto con más detalle:

return new Promise( (resolve, reject) => { Esto crea una nueva Promesa, y la Promesa te da dos devoluciones de llamada para usar. resolve es una devolución de llamada para indicar el éxito. Le pasas el objeto que te gustaría devolver. Tenga en cuenta que he eliminado el async palabra clave (más sobre esto más adelante).

Por ejemplo:

const a = new Promise( (resolve, reject) => resolve(5) );
a.then( (result) => result == 5 ); //true

(err, testData) => { Esta función se usa para mapear el estilo de nodo cb(err, result) a las devoluciones de llamadas de Promise.

Intentar/atrapar se está utilizando incorrectamente.

Try/catch solo se puede usar para declaraciones síncronas. Comparemos una llamada síncrona, un estilo de nodo (es decir, cb(err, result) ) devolución de llamada asíncrona, una Promesa y usar await:

  • Sincrónico:
try {
    let a = doSomethingSync();
} catch(err) {
    handle(err);
}
  • Asíncrono:
doSomethingAsync( (err, result) => {
    if (err) {
        handle(err);
    } else {
        let a = result;
    }
});
  • Promesa:
doSomethingPromisified()
    .then( (result) => { 
        let a = result; 
    })
    .catch( (err) => {
        handle(err);
    });
  • Espera. Await se puede usar con cualquier función que devuelva una Promesa y le permite manejar el código como si fuera sincrónico:
try {
    let a = await doSomethingPromisified();
} catch(err) {
    handle(err);
}

Información adicional

Promise.resolve()

Promise.resolve() crea una nueva Promesa y resuelve esa Promesa con un valor indefinido. Esta es la abreviatura de:

new Promise( (resolve, reject) => resolve(undefined) );

El equivalente de devolución de llamada de esto sería:

cb(err, undefined);

async

async va con await . Si está utilizando await en una función, esa función debe declararse como async .

Así como await desenvuelve una Promesa (resolve en un valor, y reject en una excepción), async envolturas código en una promesa. Un return value la declaración se traduce a Promise.resolve(value) , y una excepción lanzada throw e se traduce a Promise.reject(e) .

Considere el siguiente código

async () => {
    return doSomethingSync();
}

El código anterior es equivalente a esto:

() => {
    const p = new Promise(resolve, reject);
    try {
        const value = doSomethingSync();
        p.resolve(value);
    } catch(e) {
        p.reject(e);
    }
    return p;
}

Si llama a cualquiera de las funciones anteriores sin await , obtendrás una Promesa. Si await cualquiera de ellos, se le devolverá un valor o se lanzará una excepción.