Problémy s kódem
Dobře, je tu spousta problémů, takže nejdřív.
connection.query('...', function (err, rows) {
connection.release();
if (!err) {
return rows;
} else {
return false;
}
});
To nebude fungovat, protože vracíte data volajícímu, což je databázový dotaz, který volá zpětné volání s err
a rows
a nezajímá vás návratová hodnota vašeho zpětného volání.
Co musíte udělat, je zavolat nějakou jinou funkci nebo metodu, když máte řádky, nebo když ne.
Voláte:
var rows = loginM.findUser(req.body, res);
a očekáváte, že tam dostanete řádky, ale nedostanete. To, co dostanete, je undefined
a získáte to rychleji, než se spustí dotaz na databázi. Funguje to takto:
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 se vrátí ihned poté, co předáte funkci, ještě před připojením k databázi. Po nějaké době se může zavolat funkce, kterou jste předali této metodě, ale bude to dlouho poté, co jste již vrátili undefined
na kód, který chtěl hodnotu v:
var rows = loginM.findUser(req.body, res);
Místo vracení hodnot ze zpětných volání z nich musíte volat některé další funkce nebo metody (například některá zpětná volání, která musíte volat, nebo metodu k vyřešení příslibu).
Vrácení hodnoty je synchronní koncept a nebude fungovat pro asynchronní kód.
Jak se mají používat sliby
Nyní, pokud vaše funkce vrátila slib :
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');
}
});
});
});
}
pak jej budete moci použít v jiné části vašeho kódu takto:
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);
});
});
// ...
Vysvětlení
Stručně řečeno, pokud spouštíte asynchronní operaci - jako je databázový dotaz - pak nemůžete mít hodnotu okamžitě takto:
var value = query();
protože server by musel zablokovat čekání na databázi, než by mohl provést přiřazení – a to se děje v každém jazyce se synchronním, blokujícím I/O (proto musíte mít vlákna v těchto jazycích, aby bylo možné hotovo, dokud je vlákno blokováno).
V Node můžete buď použít funkci zpětného volání, kterou předáte asynchronní funkci, aby byla volána, když má data:
query(function (error, data) {
if (error) {
// we have error
} else {
// we have data
}
});
otherCode();
Nebo můžete dostat slib:
var promise = query();
promise.then(function (data) {
// we have data
}).catch(function (error) {
// we have error
});
otherCode();
Ale v obou případech otherCode()
bude spuštěna ihned po registraci vašich obslužných funkcí zpětného volání nebo příslibu, než bude mít dotaz nějaká data – to znamená, že není třeba provádět žádné blokování.
Shrnutí
Celá myšlenka spočívá v tom, že v asynchronním, neblokujícím, jednovláknovém prostředí, jako je Node.JS, nikdy neděláte více věcí najednou – ale můžete čekat na spoustu věcí. Ale nemusíte jen na něco čekat a nic nedělat, zatímco čekáte, naplánujete si jiné věci, čekáte na další věci a nakonec vám zavolají zpět, až to bude připraveno.
Ve skutečnosti jsem pro ilustraci tohoto konceptu napsal krátký příběh na Medium:Nonblacking I/O na planetě Asynchronia256/16 – Povídka volně založená na nejistých faktech .