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 .