Last active
December 28, 2015 14:29
-
-
Save ThomasBurleson/7514779 to your computer and use it in GitHub Desktop.
Using Promises and AngularJS $log, I demonstrate how to guard targeted function invocations using a `super` version of try-catch. And the guard will report exceptions (with stack traces) via the logger function. If the target function returns a promise, then a rejection handler is attached; which will also report rejections and possible stack tr…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Implement a tryCatch() method that logs exceptions for method invocations AND | |
* promise rejection activity. | |
* | |
* @param notifyFn Function callback with logging/exception information (typically $log.error ) | |
* @param scope Object Receiver for the notifyFn invocation ( optional ) | |
* | |
* @return Function used to guard and invoke the targeted actionFn | |
*/ | |
function makeTryCatch( notifyFn, scope ) | |
{ | |
/** | |
* Report error (with stack trace if possible) to the logger function | |
*/ | |
var isObject = function (value) | |
{ | |
return value != null && typeof value == 'object'; | |
}, | |
reportError = function (reason) | |
{ | |
if(notifyFn != null) | |
{ | |
var error = (reason && reason.stack) ? reason : null, | |
message = reason != null ? String(reason) : ""; | |
if(error != null) | |
{ | |
message = error.message + "\n" + error.stack; | |
} | |
notifyFn.apply(scope, [message]); | |
} | |
return reason; | |
}, | |
/** | |
* Publish the tryCatch() guard 'n report function | |
*/ | |
tryCatch = function (actionFn, scope, args) | |
{ | |
try | |
{ | |
// Invoke the targeted `actionFn` | |
var result = actionFn.apply(scope, args || []), | |
promise = ( isObject(result) && result.then ) ? result : null; | |
// Catch and report any promise rejection reason... | |
if ( promise ) | |
{ | |
promise.then( null, reportError ); | |
} | |
actionFn = null; | |
return result; | |
} | |
catch(e) | |
{ | |
actionFn = null; | |
throw reportError(e); | |
} | |
}; | |
return tryCatch; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@IgorMinar posted this:
How is this different from the built in error logging? Are there scenarios where the built in stuff is insufficient?
It would be useful to have a side by side comparison of the your stuff with the equivalent functionality implemented using the built-in $q.
Here is the equivalent without the
tryCatch()
macro:AngularJS $q and $log have s-tons of functionality, but when developers want a macro function that works transparently with $q Promises and outputs rejections to the $log.error or a LogEnhancer, then tryCatch() becomes very useful.
Imagine a custom service API with 10 public methods (each return a promise). Without
tryCatch()
developers would quickly lose their DRY code while attempting to log rejections and manage exceptions for each of the API calls. Developers could easily end up with lots of redundant code similar to that show above for thevideoPlayer.play( url )
function.And then we should consider the fact that logging exceptions in Promises is tricky. I contend that it is highly like that most developers are not aware of such subtle issues that require your to rethrow the exception if you do not want to interrupt the original rejection flow.
With the
tryCatch()
macro, however, consider the resulting code savings:I have found this solution to be extremely useful and reduces developer code significantly. Btw -
tryCatch()
call also be transparently used with APIs that do not return Promises; the same macro method for multiple purposes.@igor, perhaps I am missing something already available in AngularJS or some other thought you were suggesting ?