sql >> データベース >  >> NoSQL >> MongoDB

forループ(Node.JS)でコールバックを処理する方法

    この問題は、 "callbackhell" と呼ばれます。 。 Promise を使用するなど、他にも多くのアプローチがあります。 および非同期 あなたが見つけるライブラリ。

    ネイティブの<にもっと興奮しています。 code> async ES7 トランスパイラーライブラリBabel で実際に使用を開始できるようになります 。

    しかし、私が見つけた最も簡単なアプローチは次のとおりです。長いコールバック関数を取り出して、外部で定義します。

    router.route('/report') // the REST api address
        .post(calling_a_POST)
    
    function calling_a_POST(req, res) {
        ...
        var data = "";
        https.get(url, function callback(response) {
            ...
            response.on("end", response_on_end_callback); // --> take out
            response.on("error", console.error);
        });
    }
    
    function response_on_end_callback() {                 // <-- define here
        ...
        for (var i = 0; i < length; i++) {
            var report = new Report(array.pop());
            ...
            Report.find({ id: report['id'] })
                  .count(Report_find_count_callback);     // --> take out
        };
        res.json({
            message: 'Grabbed Report'
        });
    }
    
    function Report_find_count_callback(err, count) {     // <-- define here
        ...
        if (count == 0) {
            report.save(function(err) {                   // !! report is undefined here
                console.log('saved');
                if (err)
                    res.send(err);                        // !! res is undefined here
            });
        }
    }
    

    注意点は、スコープから除外したため、コールバックであったもの内のすべての変数にアクセスできないことです。

    これは、必要な変数を渡すための一種の「依存性注入」ラッパーで解決できます。

    router.route('/report') // the REST api address
        .post(calling_a_POST)
    
    function calling_a_POST(req, res) {
        ...
        var data = "";
        https.get(url, function callback(response) {
            ...
            response.on("end", function(err, data){       // take these arguments
                response_on_end(err, data, res);          // plus the needed variables
            });
            response.on("error", console.error);
        });
    }
    
    function response_on_end(err, data, res) {  // and pass them to function defined outside
        ...
        for (var i = 0; i < length; i++) {
            var report = new Report(array.pop());
            ...
            Report.find({ id: report['id'] })
                .count(function(err, count){
                    Report_find_count(err, count, report, res);  // same here
                });
        };
        res.json({                                        // res is now available
            message: 'Grabbed Report'
        });
    }
    
    function Report_find_count(err, count, report, res) {        // same here
        ...
        if (count == 0) {
            report.save(function(err) {                   // report is now available
                console.log('saved');
                if (err)
                    res.send(err);                        // res is now available
            });
        }
    }
    

    ここで間違いを犯したことに気づきました:

    function calling_a_POST(req, res) {
        ...
        var data = "";
        https.get(url, function callback(response) {
            ...
            //sponse.on("end", function(err, data){
            response.on("end", function(err){ // data shouldn't be here
                response_on_end(err, data, res);
            });
            response.on("error", console.error);
        });
    }
    

    私が予測できたもう1つの問題は、実際にはここでは発生しない可能性がありますが、とにかく話し合うほうがよいでしょう。 data 変数。オブジェクトとは異なり、プリミティブ型の文字列であるため、「値で渡されます」。詳細

    javascriptのオブジェクトは常に「参照によって渡される」ため、変数をオブジェクトでラップしてオブジェクトを渡すことをお勧めします。

    function calling_a_POST(req, res) {
        ...
        // var data = ""; // 
        var data_wrapper = {};
        data_wrapper.data = {};                                // wrap it in an object
        https.get(url, function callback(response) {
            ...
            response.on("data", function(chunk){
                data_wrapper.data += chunk.toString() + "";   // use the dot notation to reference
            });
            response.on("end", function(err){ 
                response_on_end(err, data_wrapper, res);      // and pass that object
            });
            response.on("error", console.error);
        });
    }
    
    function response_on_end_callback(err, data_wrapper, res) {
        var data = data_wrapper.data;                         // later redefine the variable
        ...
        for (var i = 0; i < length; i++) {
            var report = new Report(array.pop());
            ...
    


    1. Sparkがタスクを実行していない

    2. フレームワークを使用せずに、Node.jsを介してMongoDBからフロントエンドにデータを表示する方法

    3. TypeError:callback.applyは関数ではありません(Node.js&Mongodb)

    4. Mongoエクスポートクエリを使用できません