質問

I am trying to use async library but I don't know how to rewrite callback hell in a real world example. I am especially interested in series method combined with communication to some existing driver. Could somebody rewrite the following source code using async.js series method? It is taken from this link.

I am not fixed to MongoDb. If anybody has rewritten some other callback hell example to async series it would be nice to show.

I would also be interested in any alternative solution besides async library. But again - rewriting this example in that solution (or showing other full example), so we could see real code and compare.

var MongoClient = require('../lib/mongodb').MongoClient
  , format = require('util').format;

var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;

console.log("Connecting to " + host + ":" + port);
MongoClient.connect(format("mongodb://%s:%s/node-mongo-examples?w=1", host, port), function(err, db) {
  db.dropDatabase(function(err, result) {

    var collection = db.collection('test');
    // Erase all records from the collection, if any
    collection.remove({}, function(err, result) {
      // Insert 3 records
      for(var i = 0; i < 3; i++) {
        collection.insert({'a':i}, {w:0});
      }

      collection.count(function(err, count) {
        console.log("There are " + count + " records in the test collection. Here they are:");

        collection.find().each(function(err, item) {
          if(item != null) {
            console.dir(item);
            console.log("created at " + new Date(item._id.generationTime) + "\n")
          }

          // Null signifies end of iterator
          if(item == null) {
            // Destory the collection
            collection.drop(function(err, collection) {
              db.close();
            });
          }
        });
      });
    });
  });
});
役に立ちましたか?

解決 2

You can start by defining each of the callbacks in this nested system as functions instead. So the basic idea is instead of doing

action(data, function (err, value) { if (err) { ... } ... })

you do

action(data, namedCallback)

function namedCallback(err, value) {
     if (err) { ... }
     ....
     nextAction(value, nextNamedCallback)
}

Things you should note about this implementation

  • The variables that you want to share are defined in scope of all of the functions (see var db and var collection
  • In this implementation, all of the functions are callbacks, To use the series implementation, you need to split up the functions into functions which perform the action, not functions which handle the action when it is finished
  • You should handle the err case in your callbacks properly
var MongoClient = require('../lib/mongodb').MongoClient
    , format = require('util').format;

var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ?
  process.env['MONGO_NODE_DRIVER_HOST'] :
  'localhost';

var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ?
    process.env['MONGO_NODE_DRIVER_PORT'] :
    27017;

console.log("Connecting to " + host + ":" + port);
MongoClient.connect(
    format("mongodb://%s:%s/node-mongo-examples?w=1", host, port)
    onConnect)


var db
var collection

function onConnect(err, _db) {
    db = _db
    db.dropDatabase(onDrop);
}

function onDrop(err, result) {
    collection = db.collection('test');

    // Erase all records from the collection, if any
    collection.remove({}, onRemove);
}

function onRemove(err, result) {
      // Insert 3 records
    for(var i = 0; i < 3; i++) {
        collection.insert({ 'a': i }, { w: 0 });
    }

    collection.count(onCount)
}

function onCount(err, count) {
    console.log("There are",
        count,
        "records in the test collection. Here they are:");

    collection.find().each(onFind);
}

function onFind(err, item) {
    if (item != null) {
        console.dir(item);
        console.log("created at " + new Date(item._id.generationTime) + "\n")
    }

    // Null signifies end of iterator
    if (item == null) {
        // Destory the collection
        collection.drop(onEnd)
    }
}

function onEnd(err, item) {
    db.close();
}

他のヒント

Something like this with async.series (code not tested, provided just as reference):

var async = require('async') 
  , MongoClient = require('../lib/mongodb').MongoClient
  , format = require('util').format;

var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;
var collection, db
console.log("Connecting to " + host + ":" + port);
async.series([
    // Connect to DB
    function(callback) {
        var connectionString = format("mongodb://%s:%s/node-mongo-examples?w=1", host, port)
        MongoClient.connect(connectionString, function(err, ref) {
            if (ref) db = ref
            callback(err, ref)
        })
    },
    // Drop DB
    function(callback) {
        db.dropDatabase(callback)
    },
    // Erase all records from the collection, if any
    function(callback) {
        collection = db.collection('test');
        collection.remove({}, callback)
    },
    // Insert 3 records
    function(callback) {
        async.each(new Array(3), function(cb) {
            collection.insert({'a':i}, {w:0}, cb);
        }, callback)
    },
    //Check records count
    function(callback) {
        collection.count(function(err, count) {
            if (err) return callback(err)
            console.log("There are " + count + " records in the test collection. Here they are:");
            callback(err, count)
        })
    },
    //Indicate items
    function(callback) {
        collection.find({}, function(err, items) {
            items.forEach(function(item) {
                if(item == null) return
                console.dir(item);
                console.log("created at " + new Date(item._id.generationTime) + "\n")
            })
            callback(err, items)
        })
    },
    function(callback) {
        collection.drop(callback)
    }
], function(error, results) {
    // disconnect from DB
    error && console.error(error)
    db && db.close();
})

Or like this (mixed waterfall and series approach, no global vars):

    var async = require('async') 
  , MongoClient = require('../lib/mongodb').MongoClient
  , format = require('util').format;

var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;

console.log("Connecting to " + host + ":" + port);
async.waterfall({
    // Connect to DB
    db: function(callback) {
        var connectionString = format("mongodb://%s:%s/node-mongo-examples?w=1", host, port)
        MongoClient.connect(connectionString, callback)
    },
    // Drop DB
    collection: function(db, callback) {
        db.dropDatabase(function(err, result) {
            var collection = db.collection('test');
            callback(err, collection)
        })
    },
    collModifications: function(collection, callback) {
        async.series([
        // Erase all records from the collection, if any
            function(callback) {
                collection.remove({}, callback)
            },
            // Insert 3 records
            function(callback) {
                async.each(new Array(3), function(cb) {
                    collection.insert({'a':i}, {w:0}, cb);
                }, callback)
            },
            //Check records count
            function(callback) {
                collection.count(function(err, count) {
                    if (err) return callback(err)
                    console.log("There are " + count + " records in the test collection. Here they are:");
                    callback(err, count)
                })
            },
            //Indicate items
            function(callback) {
                collection.find({}, function(err, items) {
                    items.forEach(function(item) {
                        if(item == null) return
                        console.dir(item);
                        console.log("created at " + new Date(item._id.generationTime) + "\n")
                    })
                    callback(err, items)
                })
            },
            function(callback) {
                collection.drop(callback)
            }
        ], callback)
    }
}, function(error, results) {
    // disconnect from DB
    error && console.error(error)
    results && results.db && results.db.close();
})
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top