2

I have confusing code that I'd like to modularize. I have a general ledger implemented in Mongodb. Transferring credits from john to adam appends the following document in the db.dummyTx:

{
  "debitAccount": "john",
  "creditAccount": "adam",
  "amount": 10
}

I'd like to create a single function transfer(from, to, amount, callback()) where callback receives the transaction document/object.

I've created the following using the async module:

function transfer(from, to, amount, acallback) {
  async.waterfall([
      function(callback) {
        userBalance(from);
        userBalance(to);
        callback(null);
      },
      function(callback) {
        var transaction = new dummyTx();
        transaction.creditAccount = from; // in the account of the sender
        transaction.debitAccount = to; // with reference to the reciever
        transaction.amount = amount; // of the given amount
        transaction.save(function(err) {
          callback(null, transaction);
        });
      },
      function(transaction, callback) {
        console.log("Credited User " + transaction.creditAccount +
          " and debited User " + transaction.debitAccount + " by amount " +
          transaction.amount + "credits");
        callback(null, transaction);
      },
      function(transaction, callback) {
        userBalance(transaction.creditAccount);
        userBalance(transaction.debitAccount);
        callback(null, transaction);
      }
    ],
    acallback(err, transaction)
  );
}

My rationale was that if I pass function(err,transaction){if err console.log(err);} as acallback, it would run as the final callback in the end. However, it says err is undefined in acallback(err, transaction)

Bear with me, I just discovered async yesterday, so I'm a figurative five year old.

My second thought was to save the chain of functions into an Array named transfer and to call it as async(transfer,function(err,transaction){if err console.log(err)}; if I can't get this to work.

Edit: I'd also like the acallback parameter to be optional.

Amin Shah Gilani
  • 8,675
  • 5
  • 37
  • 79
  • Why do you ignore errors from `transaction.save`? Also, why do you use `waterfall` at all here when you have only a single async function? – Bergi May 11 '15 at 20:41
  • @Bergi It's simple really, because I'm stupid. Thank you, I've now changed it to `callback(err, transaction)`. And I just realized that I could do the same thing with `async.series`. I've got another problem now though, the `acallback` parameter now executes after the third function, with a `null` error value, and then outputs the final function normally when I run `transfer(2, 1, 2, function(err, transaction) { if (err) { console.log(transaction); }});`. [Pastebin of output](http://pastebin.com/CuN6j2yB) – Amin Shah Gilani May 11 '15 at 21:00

1 Answers1

1

If you have defined the function acallback, then you should just pass that, and not the parameters. In other words, instead of this:

...
      }
    ],
    acallback(err, transaction)
  );
}

...use this:

...
      }
    ],
    acallback
  );
}

To make acallback() optional, you can do a number of things. A couple things that leap to mind:

  • Before calling, async.waterfall(), check to see if acallback() is defined. If it is not, set it to a no-op function.

  • Before calling async.waterfall(), check to see if acallback() is defined. If it is not, invoke async.waterfall() without it. If it is, invoke it with it.

Trott
  • 66,479
  • 23
  • 173
  • 212
  • Thank you for that, the code runs now. Only, the `acallback` is executed after the third function, instead of the last. I ran it with `transfer(2,1,2,function(err, transaction){console.log(transaction);});`. [Pastebin to output](http://pastebin.com/CuN6j2yB). Also, the `to` in the third function is now `undefined`. – Amin Shah Gilani May 11 '15 at 20:22
  • If a function in the waterfall sends an error, the waterfall is aborted and the callback invoked immediately. So check the value of `err` in your callback and it will hopefully indicate what's going wrong. – Trott May 11 '15 at 20:23
  • It's `null`, however, I notice that the value of `to` in the third function is now `undefined`. – Amin Shah Gilani May 11 '15 at 20:26
  • It's `undefined` because of a typo in the code, sorry. I fixed it. However, `acallback` is still being executed after the third function, with the `err` outputing to `null` – Amin Shah Gilani May 11 '15 at 20:34