ThomasBurleson
11/17/2013 - 3:47 PM

Using Promises and AngularJS $log, I demonstrate how to guard targeted function invocations using a `super` version of try-catch. And the gu

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 traces.

/**
 * 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;
}