Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Nodejs expressa e promete não fazer o que eu espero

Problemas com o código


Ok, há muitos problemas aqui, então as primeiras coisas primeiro.
        connection.query('...', function (err, rows) {
            connection.release();
            if (!err) {
                return rows;
            } else {
                return false;
            }
        });

Isso não funcionará porque você está retornando dados para o chamador, que é a consulta do banco de dados que chama seu retorno de chamada com err e rows e não se importa com o valor de retorno do seu callback.

O que você precisa fazer é chamar alguma outra função ou método quando tiver as linhas ou não.

Você está chamando:
var rows = loginM.findUser(req.body, res);

e você espera obter as linhas lá, mas não vai. O que você obterá é undefined e você o obterá mais rápido do que a consulta ao banco de dados é iniciada. Funciona assim:
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
}

O pool.getConnection O método retorna imediatamente após você passar uma função, antes mesmo que a conexão com o banco de dados seja feita. Então, depois de algum tempo, essa função que você passou para esse método pode ser chamada, mas vai demorar muito depois que você já retornou undefined para o código que queria um valor em:
var rows = loginM.findUser(req.body, res);

Em vez de retornar valores de retornos de chamada, você precisa chamar algumas outras funções ou métodos deles (como alguns retornos de chamada que você precisa chamar ou um método para resolver uma promessa).

Retornar um valor é um conceito síncrono e não funcionará para código assíncrono.

Como as promessas devem ser usadas


Agora, se sua função retornou uma promessa :
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');
            }
        });
      });
    });
}

então você poderá usá-lo em alguma outra parte do seu código de uma maneira 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);
        });
    });
    // ...

Explicação


Em resumo, se você estiver executando uma operação assíncrona - como uma consulta de banco de dados -, não poderá ter o valor imediatamente assim:
var value = query();

porque o servidor precisaria bloquear a espera pelo banco de dados antes de poder executar a atribuição - e isso é o que acontece em todas as linguagens com E/S síncrona e de bloqueio (é por isso que você precisa ter threads nessas linguagens para que outras coisas possam ser feito enquanto esse encadeamento está bloqueado).

No Node, você pode usar uma função de retorno de chamada que você passa para a função assíncrona para ser chamada quando ela tiver dados:
query(function (error, data) {
  if (error) {
    // we have error
  } else {
    // we have data
  }
});
otherCode();

Ou você pode obter uma promessa:
var promise = query();
promise.then(function (data) {
  // we have data
}).catch(function (error) {
  // we have error
});
otherCode();

Mas em ambos os casos otherCode() será executado imediatamente após registrar seus manipuladores de retorno de chamada ou promessa, antes que a consulta tenha quaisquer dados - ou seja, nenhum bloqueio precisa ser feito.

Resumo


A ideia é que em um ambiente assíncrono, não bloqueante e de thread único como o Node.JS, você nunca faz mais de uma coisa por vez - mas pode esperar por muitas coisas. Mas você não apenas espera por algo e não faz nada enquanto espera, você agenda outras coisas, espera por mais coisas e, eventualmente, é chamado de volta quando estiver pronto.

Na verdade, escrevi um conto no Medium para ilustrar esse conceito:E/S não negra no planeta Asynchronia256/16 - Um conto vagamente baseado em fatos incertos .