Ответ 1
Проблемы с кодом
Хорошо, здесь есть много проблем, поэтому сначала сначала.
connection.query('...', function (err, rows) {
connection.release();
if (!err) {
return rows;
} else {
return false;
}
});
Это не сработает, потому что вы возвращаете данные вызывающему абоненту, который является запросом базы данных, который вызывает ваш обратный вызов с помощью err
и rows
и не заботится о возвращаемом значении вашего обратного вызова.
Что вам нужно сделать, так это вызвать другую функцию или метод, если у вас есть строки или нет.
Вы вызываете:
var rows = loginM.findUser(req.body, res);
и вы ожидаете получить там строки, но вы этого не сделаете. Вы получите undefined
, и вы получите его быстрее, чем запрос базы данных даже начался. Он работает следующим образом:
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
возвращает сразу после передачи функции до того, как будет выполнено соединение с базой данных. Затем, через некоторое время, эта функция, которую вы передали этому методу, может быть вызвана, но она будет долго после того, как вы уже вернетесь undefined
к коду, который хотел получить значение:
var rows = loginM.findUser(req.body, res);
Вместо того, чтобы возвращать значения из обратных вызовов, вам нужно вызвать из них некоторые другие функции или методы (например, некоторые обратные вызовы, которые необходимо вызвать, или метод для решения обещания).
Возврат значения является синхронной концепцией и не будет работать для асинхронного кода.
Как promises следует использовать
Теперь, если ваша функция вернула обещание:
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');
}
});
});
});
}
то вы сможете использовать его в какой-либо другой части вашего кода следующим образом:
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);
});
});
// ...
Описание
Итак, если вы выполняете асинхронную операцию - например, запрос базы данных, то вы не можете сразу иметь значение:
var value = query();
потому что серверу нужно будет блокировать ожидание базы данных до того, как он сможет выполнить назначение, - и это происходит на каждом языке с синхронным блокирующим вводом-выводом (для чего вам необходимо иметь потоки на этих языках, чтобы другие все может быть сделано, пока этот поток заблокирован).
В Node вы можете использовать функцию обратного вызова, которую вы передаете асинхронной функции для вызова, когда она имеет данные:
query(function (error, data) {
if (error) {
// we have error
} else {
// we have data
}
});
otherCode();
Или вы можете получить обещание:
var promise = query();
promise.then(function (data) {
// we have data
}).catch(function (error) {
// we have error
});
otherCode();
Но в обоих случаях otherCode()
будет запущен сразу после регистрации ваших обработчиков обратного вызова или обещания, прежде чем запрос будет иметь какие-либо данные - это не блокировка, которая должна быть выполнена.
Резюме
Вся идея заключается в том, что в асинхронной, неблокирующей, однопоточной среде, такой как Node.JS, вы никогда не делаете больше чем одну вещь за раз, но вы можете дождаться множества вещей. Но вы не просто ждёте чего-то и ничего не делаете, пока ждете, планируете другие вещи, ждете большего, и в итоге вы получите ответ, когда он будет готов.
На самом деле я написал короткую историю на Medium, чтобы проиллюстрировать эту концепцию: Неразрушающий ввод-вывод на планете Asynchronia256/16 - Краткая история, основанная на неопределенных фактах.