sql >> Databasteknik >  >> RDS >> Mysql

Nodejs uttrycker och lovar att inte göra vad jag förväntar mig

Problem med koden

Ok, det finns många problem här så först till kvarn.

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

Detta kommer inte att fungera eftersom du returnerar data till den som ringer, vilket är databasfrågan som anropar din återuppringning med err och rows och bryr sig inte om returvärdet av din återuppringning.

Vad du behöver göra är att anropa någon annan funktion eller metod när du har raderna eller när du inte har det.

Du ringer:

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

och du förväntar dig att få raderna dit, men det kommer du inte. Det du får är undefined och du får det snabbare än att databasfrågan ens startas. Det fungerar så här:

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
}

pool.getConnection metod returnerar omedelbart efter att du har skickat en funktion, innan anslutningen till databasen ens har gjorts. Sedan, efter en tid, kan funktionen som du skickade till den metoden anropas, men det kommer att dröja länge efter att du redan returnerade undefined till koden som ville ha ett värde i:

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

Istället för att returnera värden från callbacks måste du anropa några andra funktioner eller metoder från dem (som vissa callbacks som du behöver anropa, eller en metod för att lösa ett löfte).

Att returnera ett värde är ett synkront koncept och fungerar inte för asynkron kod.

Hur löften ska användas

Nu, om din funktion returnerade ett löfte :

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');
            }
        });
      });
    });
}

då kommer du att kunna använda den i någon annan del av din kod på ett sätt som detta:

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

Förklaring

Sammanfattningsvis, om du kör en asynkron operation - som en databasfråga - kan du inte ha värdet direkt så här:

var value = query();

eftersom servern skulle behöva blockera att vänta på databasen innan den kunde utföra uppdraget - och det är vad som händer i alla språk med synkron, blockerande I/O (det är därför du måste ha trådar på de språken så att andra saker kan vara gjort medan den tråden är blockerad).

I Node kan du antingen använda en återuppringningsfunktion som du skickar till den asynkrona funktionen för att bli anropad när den har data:

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

Eller så kan du få ett löfte:

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

Men i båda fallen otherCode() kommer att köras omedelbart efter att du har registrerat dina återuppringnings- eller löfteshanterare, innan frågan har några data - det betyder att ingen blockering behöver göras.

Sammanfattning

Hela tanken är att i en asynkron, icke-blockerande, entrådig miljö som Node.JS gör du aldrig mer än en sak åt gången – men du kan vänta på många saker. Men du väntar inte bara på något och gör ingenting medan du väntar, du schemalägger andra saker, väntar på fler saker och så småningom blir du uppringd när det är klart.

Jag skrev faktiskt en novell på Medium för att illustrera det konceptet:Icke-svartande I/O på planeten Asynchronia256/16 – En novell löst baserad på osäkra fakta .




  1. BESTÄLL EFTER datum och tid FÖRE GRUPP EFTER namn i mysql

  2. Det gick inte att ansluta till localDB i VS2012 – Ett nätverksrelaterat eller instansspecifikt fel inträffade när en anslutning till SQL Server upprättades...

  3. Topp 9 användbara Oracle Apps-skrivarfrågor

  4. Databasbackups - Jämför MariaDB Mariabackup och Percona Xtrabackup