CrabDude / trycatch

An asynchronous domain-based exception handler with long stack traces for node.js
MIT License
246 stars 17 forks source link

Add finally support #37

Closed CrabDude closed 8 years ago

CrabDude commented 10 years ago

For cases when you don't want the domain to leak or nest.

function doAsync(callback) {
  trycatch(function(next) {
    foo('value', next);
  }, callback, callback.bind(null, null));
}
CrabDude commented 10 years ago

@hueniverse So, I have this pretty much implemented, but I'm curious to get your feedback on the finally callback's error parameter:

Option 1

trycatch(function(finallyCallback) {
  process.nextTick(function() {
    finallyCallback(new Error('fail'), 1, 2)
  })
}, function(err) {
  // not called
}, function(err, argOne, argTwo) {
  assert.equal(err.message, 'fail')
  // argOne and argTwo only passed if err was null
})

Option 2

trycatch(function(finallyCallback) {
  process.nextTick(function() {
    finallyCallback(new Error('fail'), 1, 2)
  })
}, function(err) {
  assert.equal(err.message, 'fail')
}, function(argOne, argTwo) {
  // called after catchFn
  // argOne and argTwo only passed if err was null
})
hueniverse commented 10 years ago

So option 1 - what the middle callback?

CrabDude commented 10 years ago

both are trycatch(tryFn, catchFn, finallyFn). The distinction is whether errors passed to the finally callback are passed to the catchFn or the finallyFn.

hueniverse commented 10 years ago

I need a fuller example. I am not following how this is used with regard to where the err is coming from.

CrabDude commented 10 years ago

Clearer example:

Option 1

trycatch(function tryFn(finallyCallback) {
  process.nextTick(function() {
    var err1 = new Error('fail 1')
    throw err1
  })
  process.nextTick(function() {
    var err2 = new Error('fail 2')
    finallyCallback(err2, 1, 2)
  })
}, function catchFn(err1) {
  assert.equal(err1.message, 'fail 1')
}, function finallyFn(err2, argOne, argTwo) {
  assert.equal(err2.message, 'fail 2')
  // argOne and argTwo only passed if err2 was null
})

Option 2

trycatch(function tryFn(finallyCallback) {
  process.nextTick(function() {
    var err1 = new Error('fail 1')
    throw err1
  })
  process.nextTick(function() {
    var err2 = new Error('fail 2')
    finallyCallback(err2, 1, 2)
  })
}, function catchFn(err1anderr2) {
  // both err1 and err2 will be passed here before finallyFn is called
  assert.equal(err.message, 'fail')
}, function finallyFn(argOne, argTwo) {
  // called after err2 is passed to finallyCallback and catchFn
  // argOne and argTwo only passed if err2 was null
})
pocesar commented 10 years ago

would a promise based structure be too much overhead? the API would be "ready to use" regarding promises/A+, since 'catch' can cascade from intermediary thens, and finally is executed regardless

CrabDude commented 8 years ago

@pocesar Sorry, missed your comment. Yes. This I think would clean things up a lot, but only in the past year with the rise of Promise, async/await and babel would I have considered it.

trycatch will add a Promise API.

CrabDude commented 8 years ago

Looks like finally is non-normative, but is trivially added as an extension. A promise API will address this by making it possible (e.g., through a 3rd-party .finally() implementation).