Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Nodejs drückt aus und verspricht, nicht das zu tun, was ich erwarte

Probleme mit dem Code

Ok, hier gibt es viele Probleme, also das Wichtigste zuerst.

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

Dies funktioniert nicht, da Sie Daten an den Aufrufer zurückgeben, dh die Datenbankabfrage, die Ihren Rückruf mit err aufruft und rows und kümmert sich nicht um den Rückgabewert Ihres Callbacks.

Was Sie tun müssen, ist, eine andere Funktion oder Methode aufzurufen, wenn Sie die Zeilen haben oder wenn nicht.

Sie rufen an:

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

und Sie erwarten, die Zeilen dorthin zu bringen, aber Sie werden es nicht tun. Was Sie erhalten, ist undefined und Sie erhalten es schneller, als die Datenbankabfrage überhaupt gestartet wird. So funktioniert es:

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
}

Die pool.getConnection Die Methode kehrt sofort zurück, nachdem Sie eine Funktion übergeben haben, noch bevor die Verbindung zur Datenbank hergestellt wurde. Dann wird nach einiger Zeit diese Funktion, die Sie an diese Methode übergeben haben, möglicherweise aufgerufen, aber es wird lange dauern, bis Sie bereits undefined zurückgegeben haben zu dem Code, der einen Wert haben wollte in:

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

Anstatt Werte von Rückrufen zurückzugeben, müssen Sie einige andere Funktionen oder Methoden von ihnen aufrufen (wie einige Rückrufe, die Sie aufrufen müssen, oder eine Methode, um ein Promise aufzulösen).

Das Zurückgeben eines Werts ist ein synchrones Konzept und funktioniert nicht für asynchronen Code.

Wie Versprechungen verwendet werden sollten

Nun, wenn Ihre Funktion ein Promise zurückgegeben hat :

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

dann können Sie es in einem anderen Teil Ihres Codes wie folgt verwenden:

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

Erklärung

Zusammenfassend lässt sich sagen, dass Sie, wenn Sie eine asynchrone Operation wie eine Datenbankabfrage ausführen, den Wert nicht sofort wie folgt haben können:

var value = query();

weil der Server das Warten auf die Datenbank blockieren müsste, bevor er die Zuweisung ausführen könnte - und das passiert in jeder Sprache mit synchroner, blockierender E/A (deshalb müssen Sie Threads in diesen Sprachen haben, damit andere Dinge möglich sind getan, während dieser Thread blockiert ist).

In Node können Sie entweder eine Rückruffunktion verwenden, die Sie an die asynchrone Funktion übergeben, um aufgerufen zu werden, wenn sie Daten enthält:

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

Oder Sie erhalten ein Versprechen:

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

Aber in beiden Fällen otherCode() wird unmittelbar nach der Registrierung Ihres Callback- oder Promise-Handlers ausgeführt, bevor die Abfrage Daten enthält - das heißt, es muss keine Blockierung vorgenommen werden.

Zusammenfassung

Die ganze Idee ist, dass Sie in einer asynchronen, nicht blockierenden Single-Thread-Umgebung wie Node.JS nie mehr als eine Sache gleichzeitig tun – aber Sie können auf viele Dinge warten. Aber Sie warten nicht einfach auf etwas und tun nichts, während Sie warten, Sie planen andere Dinge, warten auf mehr Dinge und werden schließlich zurückgerufen, wenn es fertig ist.

Eigentlich habe ich eine Kurzgeschichte auf Medium geschrieben, um dieses Konzept zu veranschaulichen:Nonblacking I/O auf dem Planeten Asynchronia256/16 - Eine Kurzgeschichte, die lose auf unsicheren Fakten basiert .