Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Nodejs wyraża i obiecuje nie robić tego, czego oczekuję

Problemy z kodem

Ok, jest tu wiele problemów, więc najpierw najważniejsze.

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

To nie zadziała, ponieważ zwracasz dane do wywołującego, który jest zapytaniem bazy danych, które wywołuje twoje wywołanie zwrotne z err i rows i nie dba o wartość zwrotną twojego wywołania zwrotnego.

To, co musisz zrobić, to wywołać inną funkcję lub metodę, gdy masz wiersze lub nie.

Dzwonisz:

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

i spodziewasz się, że dostaniesz tam wiersze, ale tego nie zrobisz. Otrzymasz undefined a otrzymasz go szybciej, niż nawet rozpocznie się zapytanie do bazy danych. Działa to tak:

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 Metoda powraca natychmiast po przekazaniu funkcji, jeszcze przed nawiązaniem połączenia z bazą danych. Następnie, po pewnym czasie, funkcja, którą przekazałeś do tej metody, może zostać wywołana, ale minie dużo czasu po tym, jak już zwróciłeś undefined do kodu, który żądał wartości w:

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

Zamiast zwracać wartości z wywołań zwrotnych, musisz wywołać z nich inne funkcje lub metody (takie jak niektóre wywołania zwrotne, które musisz wywołać lub metoda do rozwiązania obietnicy).

Zwracanie wartości jest koncepcją synchroniczną i nie będzie działać w przypadku kodu asynchronicznego.

Jak należy używać obietnic

Teraz, jeśli Twoja funkcja zwróciła obietnicę :

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

wtedy będziesz mógł użyć go w innej części kodu w taki sposób:

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

Wyjaśnienie

Podsumowując, jeśli uruchamiasz operację asynchroniczną – taką jak zapytanie do bazy danych – nie możesz mieć wartości od razu tak:

var value = query();

ponieważ serwer musiałby blokować oczekiwanie na bazę danych, zanim mógłby wykonać przypisanie - i tak dzieje się w każdym języku z synchronicznym, blokującym I/O (dlatego trzeba mieć wątki w tych językach, aby inne rzeczy mogły być zrobić, gdy ten wątek jest zablokowany).

W Node możesz użyć funkcji zwrotnej, którą przekazujesz do funkcji asynchronicznej, aby zostać wywołana, gdy ma dane:

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

Możesz też otrzymać obietnicę:

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

Ale w obu przypadkach otherCode() zostanie uruchomiony natychmiast po zarejestrowaniu obsługi połączeń zwrotnych lub obietnic, zanim zapytanie będzie zawierało jakiekolwiek dane - to znaczy, że nie trzeba wykonywać blokowania.

Podsumowanie

Cała idea polega na tym, że w asynchronicznym, nieblokującym, jednowątkowym środowisku, takim jak Node.JS, nigdy nie robisz więcej niż jednej rzeczy naraz - ale możesz czekać na wiele rzeczy. Ale nie czekasz tylko na coś i nie robisz nic podczas czekania, planujesz inne rzeczy, czekasz na więcej rzeczy i ostatecznie zostajesz oddzwoniony, gdy wszystko będzie gotowe.

Właściwie napisałem krótkie opowiadanie na Medium, aby zilustrować tę koncepcję:Niezaczerniające I/O na planecie Asynchronia256/16 - Krótka historia luźno oparta na niepewnych faktach .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. DAYOFMONTH() Przykłady – MySQL

  2. używając (-) myślnika w nazwie tabeli mysql

  3. Jak zwrócić pozycję pozycji listy w MySQL?

  4. Zamień na składnię zapytania

  5. MySQL - ORDER BY wartości w IN()