sql >> Databáze >  >> NoSQL >> MongoDB

Jak zpracovat zpětná volání ve smyčce for (Node.JS)

Tento problém se nazývá "callback hell" .Existuje mnoho dalších přístupů, jako je použití Promise a Async knihovny, které najdete.

Jsem nadšenější z nativního async ES7 přinese, kterou můžete začít používat již dnes s knihovnou transpilerů Babel .

Ale zdaleka nejjednodušší přístup, který jsem našel, je následující:Vyjmete funkce dlouhého zpětného volání a definujete je venku.

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

Upozornění je, že nebudete mít přístup ke všem proměnným uvnitř toho, co bývalo zpětným voláním, protože jste je vyjmuli z rozsahu.

To by mohlo být vyřešeno obalem typu „injekce závislosti“, aby se předaly požadované proměnné.

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

Uvědomuji si, že jsem zde udělal chybu:

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

Další problém, který jsem mohl předvídat, který zde ve skutečnosti nemusí nastat, ale přesto by bylo lepší o něm mluvit. data proměnná, protože je to řetězec, který je na rozdíl od objektu primitivního typu, je "předán hodnotou". Další informace

Je lepší zabalit proměnnou do objektu a předat objekt, protože objekty v javascriptu jsou vždy "předány odkazem".

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. Mongo Atlas:Ověření připojení selhalo u vlastních databází

  2. ekvivalent mongodb num_rows php

  3. MongoDB - MySQL SUM (CASE WHEN) Ekvivalent?

  4. Výkon MongoDB na agregační dotazy