0

I have a multi-step process that I'd like to find a better pattern for. Let's say there's an order that you need to create revenue records for to eventually prepare an invoice. I have 4 calls to callback functions that need to happen in order. The callbacks are typically like the one here:

getRevenue(item.ID,
  function(revenueRecords) //on success
  {..do whatever to revenue here...}, 
  function(errorMsg) //on failure
  {..show error msg here...});

So in my code I need 4 of them like this:

  getRevenue
    getNewInvoice#
      (create invoice details)
      saveRevenue
        (mark order as billed)
        saveOrder
          (alert user we succeeded)

Of course each one has to have a failure function as well and it gets pretty ugly. I'm aware that $q.defer can let me combine promises and only return when they are all complete, but this process requires the steps to be sequential. I wondered if there was a better pattern for solving multi-step sequential processes involving callbacks.

James Bell
  • 889
  • 2
  • 10
  • 16
  • Please see: http://stackoverflow.com/questions/27401304/angularjs-why-promises-q-with-http/27401712#27401712 – Ben Diamant Dec 16 '14 at 14:41
  • try [async.waterfall](https://github.com/caolan/async#waterfall) from [async](https://github.com/caolan/async) – shawnzhu Dec 16 '14 at 14:45

2 Answers2

0

You can chain promises for sequential processing:

Assuming all your async calls are returning a promise, chaining would look like this:

getRevenue(item.ID)
  .then(function(revenueRecords){
     //..do whatever to revenue here...
     return getNewInvoiceNum(record)
  }
  .then(function(invoiceNum){
     //..create invoice details...
     return saveRevenue()
  }
  .then(function(invoiceNum){
     //..mark order as billed...
     return saveOrder();
  }
  .then(function(isSuccess)){
     //..alert user we succeeded...
  }
  .catch(function(error)){
     // deal with any `rejects` that could happen
  }
New Dev
  • 48,427
  • 12
  • 87
  • 129
  • This looks neat as it stands but I guess my problem is that I wanted some useful feedback at each step if there's an error, and I have a few lines of processing to do in each of the success areas. When you add those to the chain above isn't much better than the async version as far as readability. I guess I was hoping for a magic solution like q.all() has for combining promises. – James Bell Dec 16 '14 at 20:09
  • The difference is that `.catch` catches all of the rejects. A returned "reject" causes cascading rejects. – New Dev Dec 16 '14 at 20:11
0

I decided this was a case where most of the "action" was server-side and I should really be doing this there. I created new API routes for adding revenue/expense lines, bundled up the invoice details and handled 75% of it there. Much simpler and the new API calls are likely to be used elsewhere in the future.

James Bell
  • 889
  • 2
  • 10
  • 16