mark
mark

Reputation: 62712

Looking for a mainstream way to manage asynchronous flow in a nodejs application

I have this simple nodejs application, which generates dummy date for my web application. All it does is:

  1. Drops the dummy database
  2. Populates the inventory collection
  3. Populates the invoices collection
  4. Populates the const data collection

Of course, all the actions are asynchronous and I want to execute them sequentially, one after another. For me, it was simpler to write something to manage this kind of the flow, however, I would like a mainstream solution, which would support other kinds of flows. For instance, running in parallel and stopping all on the first failure.

For your reference, please, find below the skeleton, depicting my solution:

/*global require, console, process*/

var mongo, db, inventory, createChain;

function generateInventory(count) {
  // returns the generated inventory
}

function generateInvoices(count, inventory) {
  // returns the generated invoices
}

function generateConst() {
  // returns the generated const data
}

mongo = require('mongojs');
db = mongo.connect('dummy', ['invoices', 'const', 'inventory']);

createChain = function () {
  "use strict";
  var chain = [false], i = 0;

  return {
    add: function (action, errMsg, resultCallback) {
      chain[chain.length - 1] = {action: action, errMsg: errMsg, resultCallback: resultCallback};
      chain.push(false);
      return this;
    },
    invoke: function (exit) {
      var str, that = this;
      if (chain[i]) {
        chain[i].action(function (err, o) {
          if (err || !o) {
            str = chain[i].errMsg;
            if (err && err.message) {
              str = str + ": " + err.message;
            }
            console.log(str);
          } else {
            if (chain[i].resultCallback) {
              chain[i].resultCallback(o);
            }
            i += 1;
            that.invoke(exit);
          }
        });
      } else {
        console.log("done.");
        if (exit) {
          process.exit();
        }
      }
    }
  };
};

createChain()
  .add(function (callback) {
    "use strict";
    console.log("Dropping the dummy database.");
    db.dropDatabase(callback);
  }, "Failed to drop the dummy database")
  .add(function (callback) {
    "use strict";
    console.log("Populating the inventory.");
    db.inventory.insert(generateInventory(100), callback);
  }, "Failed to populate the inventory collection", function (res) {
    "use strict";
    inventory = res;
  })
  .add(function (callback) {
    "use strict";
    console.log("Populating the invoices.");
    db.invoices.insert(generateInvoices(10, inventory), callback);
  }, "Failed to populate the invoices collection")
  .add(function (callback) {
    "use strict";
    console.log("Populating the const.");
    db["const"].insert(generateConst(), callback);
  }, "Failed to populate the const collection")
  .invoke(true);

Can anyone suggest a relevant nodejs package, which would also be easy to use?

Thank you very much.

Upvotes: 0

Views: 387

Answers (2)

Grant Li
Grant Li

Reputation: 973

Actually, for sequential flow control, you should use waterfall

As an example:

async.waterfall([
  function(cb){
    cb(null,1);
  },
  function(r,cb){
    // r=1
    cb(null,2)
  },
  function(r,cb){
    // r=2
    cb(null,3)
  }
],function(e,r){
    // e=null
    // r=3
})

This will execute sequentially. If you callback an error early, (i.e. cb("error")), then it will directly go to the final function(e,r), with e="error" and r=undefined Notice how function(r,cb){} can become precomposed in a util library to handle commonly reused blocks and make things in the future easier.

Upvotes: 0

JohnnyHK
JohnnyHK

Reputation: 311835

Use the async module to provide just about any type of flow control you're ever likely to need. In particular, the series method provides sequential flow control.

Upvotes: 2

Related Questions