非同期メソッドにおけるmap、forEach、forサイクルにおける非同期実行の問題


キーワード:map()forEach()for()非同期実行res.jsonp()
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]:
异步方法中map、forEach和for循环中带来的异步执行问题_第1张图片
すると、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は空ではありません
异步方法中map、forEach和for循环中带来的异步执行问题_第2张图片
resultの書順もコードに書かれている順序と同じです
异步方法中map、forEach和for循环中带来的异步执行问题_第3张图片
ここまで見ると、やはり非同期の問題が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にデータが表示されます.
异步方法中map、forEach和for循环中带来的异步执行问题_第4张图片
サーバコンソールの効果は下図のようにarray_が表示されます.testはresultの前に印刷され、同期の順序です.
异步方法中map、forEach和for循环中带来的异步执行问题_第5张图片
詳細はasyncについては、公式ドキュメントまたはgithub中国語ドキュメントを参照してください.
もちろんbluebird、asyncawaitなど、この問題を解決する方法もありますが、ここではあまり分析しません.