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 .