Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

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.

share|improve this question
    
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 – amingilani May 11 '15 at 21:00
up vote 1 down vote accepted

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.

share|improve this answer
    
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. Also, the to in the third function is now undefined. – amingilani 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. – amingilani 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 – amingilani May 11 '15 at 20:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.