非同期メソッドにおけるmap、forEach、forサイクルにおける非同期実行の問題
8906 ワード
キーワード:map()forEach()for()非同期実行res.jsonp()
CSDN個人ブログ:http://blog.csdn.net/sam976
問題の説明
mapサイクルでmongoseのModelを使用する.findOneはmongodbデータベースをクエリーし、データをクエリーした後にres.jsonp応答を使用します.コードは次のとおりです.
ページ送信要求http://127.0.0.1:3000/getdataの場合、jsonpが返すデータは空、すなわちresultは空です.
結果は図のようになります.
まず、クエリーの結果は空ではないことは間違いありません.クエリー条件は専門的に設定されているからです.
わかってるよforEach .mapは同期(ブロック)されています.つまり、ループが終了すると、後の文が実行されます.この論理に従うと、jsonpが返すresultが空にならない場合、問題はどこですか.
もんだいぶんせき
分析によると、クエリの結果は空ではありません.これはサーバコンソールの印刷結果からわかります.図黄色の部分がクエリー結果が付与されたarray_test[i]:
すると、result印刷の場所(赤枠部分)がarray_にあることがわかります.test[i]結果の前に、これはコードの順序と合わないですね.非同期実行になりました.
mongoseドキュメントを検索すると、Model.findOne([conditions],[projection],[options],[callback])は非同期で実行される関数で、結果としてcallbackが呼び出されます.Nodeのmap()、forEach()、for()ループには、関数にコールバックがあると非同期になるという特性があります.mapはこのようになって、1回目のループが開始して、findOneはデータベースを問合せて、結果があるのを待たずに2回目のクエリが開始して、...3回目のクエリが開始して、ループが終了して、結果があるのを待たずにconsoleを実行します.log(result)なのでresultは空で、印刷結果はarray_test[i]の前に.
分析が正しいかどうかを証明するために、簡単に測定しました.findOneが非同期関数である以上、mapで非同期関数を使わないと、印刷順序とコードの書く順序が同じではないでしょうか.コードは次のとおりです.
結果は次のとおりです.
jsonpが返すresultは空ではありません
resultの書順もコードに書かれている順序と同じです
ここまで見ると、やはり非同期の問題がresultを空にしていることがわかります.どうやって解決するの?
解決策
この場合、asyncはnodejsの非同期問題を解決するためにnodejsのコンポーネントであるasyncのmapで処理することができる.mapメソッドは次のとおりです.
コレクション内の各要素に対して、非同期操作を実行し、結果を得ます.すべての結果は最終callbackにまとめられます.実は非同期をキューに追加し、すべて実行した後に統一的なコールバックを実行することで、同期の効果のように見えます.
コードは次のとおりです.
ページの効果は、resultにデータが表示されます.
サーバコンソールの効果は下図のようにarray_が表示されます.testはresultの前に印刷され、同期の順序です.
詳細はasyncについては、公式ドキュメントまたはgithub中国語ドキュメントを参照してください.
もちろんbluebird、asyncawaitなど、この問題を解決する方法もありますが、ここではあまり分析しません.
CSDN個人ブログ:http://blog.csdn.net/sam976
問題の説明
mapサイクルでmongoseのModelを使用する.findOneはmongodbデータベースをクエリーし、データをクエリーした後にres.jsonp応答を使用します.コードは次のとおりです.
router.get('/getData', function(req, res) {
var data=[1,2,3];
var result=data.map(function(v, i, a) {
/* studentid */
Fee.findOne({
studentid: "57b525bc4e8d464803167da7"
}, {}, function(err, fees) {
if (err) return handleError(err);
var array_test = [];
array_test[i] = {};
array_test[i].number = v;
array_test[i].fees = fees;
/* */
console.log('++++++array_test[i]++++++')
console.log(array_test[i])
console.log('++++++array_test[i]++++++')
return array_test[i];
});
});
/*result */
console.log('-----result-----');
console.log(result);
console.log('-----result-----');
res.jsonp({
one: 'aa',
two: 'bb',
three: result
});
});
ページ送信要求http://127.0.0.1:3000/getdataの場合、jsonpが返すデータは空、すなわちresultは空です.
結果は図のようになります.
まず、クエリーの結果は空ではないことは間違いありません.クエリー条件は専門的に設定されているからです.
わかってるよforEach .mapは同期(ブロック)されています.つまり、ループが終了すると、後の文が実行されます.この論理に従うと、jsonpが返すresultが空にならない場合、問題はどこですか.
もんだいぶんせき
分析によると、クエリの結果は空ではありません.これはサーバコンソールの印刷結果からわかります.図黄色の部分がクエリー結果が付与されたarray_test[i]:
すると、result印刷の場所(赤枠部分)がarray_にあることがわかります.test[i]結果の前に、これはコードの順序と合わないですね.非同期実行になりました.
mongoseドキュメントを検索すると、Model.findOne([conditions],[projection],[options],[callback])は非同期で実行される関数で、結果としてcallbackが呼び出されます.Nodeのmap()、forEach()、for()ループには、関数にコールバックがあると非同期になるという特性があります.mapはこのようになって、1回目のループが開始して、findOneはデータベースを問合せて、結果があるのを待たずに2回目のクエリが開始して、...3回目のクエリが開始して、ループが終了して、結果があるのを待たずにconsoleを実行します.log(result)なのでresultは空で、印刷結果はarray_test[i]の前に.
分析が正しいかどうかを証明するために、簡単に測定しました.findOneが非同期関数である以上、mapで非同期関数を使わないと、印刷順序とコードの書く順序が同じではないでしょうか.コードは次のとおりです.
router.get('/getData', function(req, res) {
var data = [1, 2, 3];
var result = data.map(function(v, i, a) {
var array_test = [];
array_test[i] = {};
array_test[i].number = v;
array_test[i].fees = 'cc';
return array_test[i];
});
console.log('-----result-----');
console.log(result);
console.log('-----result-----');
res.jsonp({
one: 'aa',
two: 'bb',
three: result
});
});
結果は次のとおりです.
jsonpが返すresultは空ではありません
resultの書順もコードに書かれている順序と同じです
ここまで見ると、やはり非同期の問題がresultを空にしていることがわかります.どうやって解決するの?
解決策
この場合、asyncはnodejsの非同期問題を解決するためにnodejsのコンポーネントであるasyncのmapで処理することができる.mapメソッドは次のとおりです.
コレクション内の各要素に対して、非同期操作を実行し、結果を得ます.すべての結果は最終callbackにまとめられます.実は非同期をキューに追加し、すべて実行した後に統一的なコールバックを実行することで、同期の効果のように見えます.
コードは次のとおりです.
/* , async.map 。*/
router.get('/getData', function(req, res) {
var data = [1, 2, 3];
var array_test = {};
async.map(data, function(v, callback) {
/* studentid */
Fee.findOne({
studentid: "57b525bc4e8d464803167da7"
}, {}, function(err, fees) {
if (err) return handleError(err);
array_test[v]=fees.studentid;
console.log('++++++array_test++++++')
console.log(array_test);
console.log('++++++array_test++++++')
callback(null, array_test);
});
}, function(err, results) {
console.log('-----result-----');
console.log(results);
console.log('-----result-----');
res.jsonp({
one: 'aa',
two: 'bb',
three: results
});
});
});
ページの効果は、resultにデータが表示されます.
サーバコンソールの効果は下図のようにarray_が表示されます.testはresultの前に印刷され、同期の順序です.
詳細はasyncについては、公式ドキュメントまたはgithub中国語ドキュメントを参照してください.
もちろんbluebird、asyncawaitなど、この問題を解決する方法もありますが、ここではあまり分析しません.