sql >> Database >  >> NoSQL >> MongoDB

Hoe om te gaan met callbacks in een for-lus (Node.JS)

Dit probleem wordt de "callback hell" genoemd. .Er zijn veel andere benaderingen, zoals het gebruik van Promise en Async bibliotheken die je zult vinden.

Ik ben meer enthousiast over de native async ES7 zal brengen, die u vandaag daadwerkelijk kunt gaan gebruiken met transpiler-bibliotheek Babel .

Maar verreweg de eenvoudigste aanpak die ik heb gevonden, is de volgende:je haalt de lange terugbelfuncties eruit en definieert ze buiten.

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
        });
    }
}

Een waarschuwing is dat u geen toegang kunt krijgen tot alle variabelen binnen wat vroeger de callback was, omdat u ze uit het bereik hebt gehaald.

Dit kan worden opgelost met een soort "dependency injection"-wrapper om de vereiste variabelen door te geven.

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
        });
    }
}

Ik realiseer me dat ik hier een fout heb gemaakt:

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);
    });
}

Een ander probleem dat ik kon voorzien, dat zich hier misschien niet voordoet, maar toch beter is om over te praten. De data variabele, aangezien het een string is die een primitief type is in tegenstelling tot een object, wordt deze "doorgegeven door waarde". Meer info

Het is beter om de variabele in een object te wikkelen en het object door te geven, omdat objecten in javascript altijd "door verwijzing worden doorgegeven".

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. MongoDb 2.6.1 Fout:17444 - Verouderd punt is buiten bereik voor sferische zoekopdrachten

  2. Kan mongodb niet importeren

  3. Hoe kan ik MongoWaitQueueFullException oplossen?

  4. FluentMongo gooit ineens fout