sql >> Base de Datos >  >> RDS >> Mysql

Nodejs expresa y promete no hacer lo que espero

Problemas con el código

Vale, aquí hay muchos problemas, así que lo primero es lo primero.

        connection.query('...', function (err, rows) {
            connection.release();
            if (!err) {
                return rows;
            } else {
                return false;
            }
        });

Esto no funcionará porque está devolviendo datos a la persona que llama, que es la consulta de la base de datos que llama a su devolución de llamada con err y rows y no le importa el valor de retorno de su devolución de llamada.

Lo que debe hacer es llamar a alguna otra función o método cuando tenga las filas o cuando no las tenga.

Estás llamando:

var rows = loginM.findUser(req.body, res);

y espera obtener las filas allí, pero no lo hará. Lo que obtendrá es undefined y lo obtendrá más rápido de lo que se inicia la consulta de la base de datos. Funciona así:

me.findUser = function(params, res) {
    // (1) you save the username in a variable
    var username = params.username;

    // (2) you pass a function to getConnection method
    pool.getConnection(function (err, connection) {
        console.log("Connection ");

        if (err) {
            console.log("ERROR 1 ");
            res.send({"code": 100, "status": "Error in connection database"});
            return;
        }

        connection.query('select Id, Name, Password from Users ' +
            'where Users.Name = ?', [username], function (err, rows) {
            connection.release();
            if (!err) {
                return rows;
            } else {
                return false;
            }
        });

        //connection.on('error', function (err) {
        //    res.send({"code": 100, "status": "Error in connection database"});
        //    return;
        //});
    });

    // (3) you end a function and implicitly return undefined
}

El pool.getConnection El método regresa inmediatamente después de pasar una función, incluso antes de que se realice la conexión a la base de datos. Luego, después de un tiempo, es posible que se llame a la función que pasó a ese método, pero pasará mucho tiempo después de que ya devolvió undefined al código que quería un valor en:

var rows = loginM.findUser(req.body, res);

En lugar de devolver valores de las devoluciones de llamada, debe llamar a otras funciones o métodos desde ellas (como algunas devoluciones de llamada a las que debe llamar o un método para resolver una promesa).

Devolver un valor es un concepto síncrono y no funcionará para el código asíncrono.

Cómo se deben usar las promesas

Ahora, si su función devuelve una promesa :

me.findUser = function(params, res) {
    var username = params.username;

    return new Promise(function (res, rej) {

      pool.getConnection(function (err, connection) {
        console.log("Connection ");

        if (err) {
          rej('db error');
        } else {
          connection.query('...', [username], function (err, rows) {
            connection.release();
            if (!err) {
                res(rows);
            } else {
                rej('other error');
            }
        });
      });
    });
}

entonces podrá usarlo en alguna otra parte de su código de una manera como esta:

app.post('/login/', function(req, res, next) {

    var promise = new Promise(function (resolve, reject) {

        // rows is a promise now:
        var rows = loginM.findUser(req.body, res);

        rows.then(function (rowsValue) {
            console.log("Success");
            resolve(rowsValue);
        }).catch(function (err) {
            console.log("Failed");
            reject(err);
        });
    });
    // ...

Explicación

En resumen, si está ejecutando una operación asincrónica, como una consulta de base de datos, entonces no puede tener el valor inmediatamente como este:

var value = query();

porque el servidor necesitaría bloquear la espera de la base de datos antes de poder ejecutar la asignación, y esto es lo que sucede en todos los idiomas con E/S de bloqueo sincrónico (es por eso que necesita tener subprocesos en esos idiomas para que otras cosas puedan ser hecho mientras ese hilo está bloqueado).

En Node, puede usar una función de devolución de llamada que pasa a la función asíncrona para que la llamen cuando tenga datos:

query(function (error, data) {
  if (error) {
    // we have error
  } else {
    // we have data
  }
});
otherCode();

O puede obtener una promesa:

var promise = query();
promise.then(function (data) {
  // we have data
}).catch(function (error) {
  // we have error
});
otherCode();

Pero en ambos casos otherCode() se ejecutará inmediatamente después de registrar su devolución de llamada o controladores de promesa, antes de que la consulta tenga datos, es decir, no es necesario realizar ningún bloqueo.

Resumen

La idea general es que en un entorno asíncrono, sin bloqueos y de un solo subproceso como Node.JS, nunca hace más de una cosa a la vez, pero puede esperar muchas cosas. Pero no solo esperas algo y no haces nada mientras esperas, programas otras cosas, esperas más cosas y finalmente te llaman cuando está listo.

De hecho, escribí una historia corta en Medium para ilustrar ese concepto:E/S sin ennegrecimiento en el planeta Asynchronia256/16 - Una historia corta basada libremente en hechos inciertos .