Mysql
 sql >> Database >  >> RDS >> Mysql

Nodejs esprime e promette di non fare quello che mi aspetto

Problemi con il codice

Ok, ci sono molti problemi qui, quindi per prima cosa.

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

Questo non funzionerà perché stai restituendo dati al chiamante, che è la query del database che richiama la tua richiamata con err e rows e non si preoccupa del valore di ritorno della tua richiamata.

Quello che devi fare è chiamare qualche altra funzione o metodo quando hai le righe o quando non le hai.

Stai chiamando:

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

e ti aspetti di ottenere le righe lì, ma non lo farai. Quello che otterrai è undefined e lo otterrai più velocemente di quanto non venga avviata la query del database. Funziona così:

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
}

Il pool.getConnection il metodo ritorna immediatamente dopo aver passato una funzione, prima ancora che venga stabilita la connessione al database. Quindi, dopo un po' di tempo, la funzione che hai passato a quel metodo potrebbe essere chiamata, ma passerà molto tempo dopo che hai già restituito undefined al codice che voleva un valore in:

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

Invece di restituire valori dai callback, devi chiamare altre funzioni o metodi da essi (come alcuni callback che devi chiamare o un metodo per risolvere una promessa).

La restituzione di un valore è un concetto sincrono e non funzionerà per il codice asincrono.

Come dovrebbero essere usate le promesse

Ora, se la tua funzione ha restituito una 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');
            }
        });
      });
    });
}

quindi sarai in grado di usarlo in qualche altra parte del tuo codice in un modo come questo:

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);
        });
    });
    // ...

Spiegazione

In sintesi, se stai eseguendo un'operazione asincrona, come una query di database, non puoi avere il valore immediatamente in questo modo:

var value = query();

perché il server dovrebbe bloccare l'attesa del database prima di poter eseguire l'assegnazione - e questo è ciò che accade in ogni lingua con I/O sincrono e bloccante (ecco perché è necessario disporre di thread in quelle lingue in modo che altre cose possano essere fatto mentre quel thread è bloccato).

In Node puoi utilizzare una funzione di callback che passi alla funzione asincrona per essere chiamata quando ha dati:

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

Oppure puoi ottenere una promessa:

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

Ma in entrambi i casi otherCode() verrà eseguito immediatamente dopo la registrazione dei gestori di callback o promesse, prima che la query contenga dati:non è necessario eseguire alcun blocco.

Riepilogo

L'idea è che in un ambiente asincrono, non bloccante e a thread singolo come Node.JS non si fa mai più di una cosa alla volta, ma si possono aspettare molte cose. Ma non aspetti solo qualcosa e non fai nulla mentre aspetti, pianifichi altre cose, aspetti altre cose e alla fine vieni richiamato quando è pronto.

In realtà ho scritto un racconto su Medium per illustrare quel concetto:I/O non blacking sul pianeta Asynchronia256/16 - Un racconto vagamente basato su fatti incerti .