コードの問題
さて、ここにはたくさんの問題があるので、まず最初に。
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);
コールバックから値を返す代わりに、それらから他のいくつかの関数またはメソッドを呼び出す必要があります(呼び出す必要のあるいくつかのコールバック、またはpromiseを解決するためのメソッドなど)。
値を返すことは同期の概念であり、非同期コードでは機能しません。
プロミスの使用方法
ここで、関数が約束を返した場合 :
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();
サーバーは、割り当てを実行する前にデータベースの待機をブロックする必要があるためです。これは、同期ブロックI / Oを使用するすべての言語で発生することです(そのため、他のことを実行できるように、これらの言語でスレッドを作成する必要があります。そのスレッドがブロックされている間に行われます。
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()
コールバックまたはPromiseハンドラーを登録した直後、クエリにデータが含まれる前に実行されます。つまり、ブロッキングを行う必要はありません。
概要
全体的な考え方は、Node.JSのような非同期の非ブロッキングシングルスレッド環境では、一度に複数のことを行うことは決してないということですが、多くのことを待つことができます。しかし、あなたはただ何かを待っているだけでなく、待っている間は何もしません。他のことをスケジュールし、さらに多くのことを待ち、最終的には準備ができたときにコールバックされます。
実際、私はその概念を説明するためにMediumに短編小説を書きました:惑星の非黒化I / O Asynchronia256/16-不確かな事実に大まかに基づいた短編小説 。