Is there a way to inject a try catch inside a function?

798 views Asked by At

Maybe some of you know about AOP, in some languages using AOP can lead you to be able to inject code after, before, or while a method is executing,etc.

What I want is to apply the same in Javascript, I am currently working on a massive app which has more than 300 ajax calls, and every time I need to do some change on the catch statement on them, I have to modify them one by one which is very tedious.

What I want to do is something like :

functionName.before("try {")

functionName.after("} catch(ex){
//dostuff
}")

Is it possible? I know there are things like .call, or the arguments object inside every function..which seem pretty meta-function (AOP) functionalities.

4

There are 4 answers

1
Bergi On BEST ANSWER

Not with before and after, but a wrap will work:

Function.prototype.wrapTry = function(handle) {
    var fn = this;
    return function() {
        try {
            return fn.apply(this, arguments);
        } catch(e) {
            return handle(e);
        }
    };
};

Then use it like

var safeFunction = functionName.wrapTry(doStuff);
0
André Pavan On

In JavaScript, functions are first-class objects. That means you can manipulate or redeclare them.

Assuming that there is a "foo" function:

var originalFoo = foo;
foo = function()
{
    // "before" code.

    // Call the original function.
    originalFoo.apply(this, arguments);

    // "after" code.
};

After that, any call to foo() will call the new function: even with parameters.

0
k1r0s On

Old question but you may take a look over this https://github.com/k1r0s/kaop-ts/blob/master/docs/api.md#available-join-points

import { onException } from "kaop-ts"
import handlingException from "./somewhere"

class Something {

  @onException(handlingException)
  method() {
    // stuff that may throw an error
  }
}
0
Peter Seliger On

I also will give a late answer in order to shed some light onto this special case that every then and now pops up as JavaScript and AOP.

Firstly, cases like the very one presented by the OP always ask for modifying already existing functionality, thus targeting closed code that sometimes is not even owned by the party that sees itself challenged from modifying the control flow of such code.

Why then, not just name it like that ... JavaScript method modification or JavaScript method modifiers.

Secondly, because of already riding the horse of terminology, altering closed functionality in JavaScript has nothing to do with Aspect-oriented Programming unless an implementation that claims to be AO provides abstraction and code-reuse levels for at least Aspect, Advice and Pointcut.

Last, for what the OP is going to achieve and what also has been the accepted answer, there does exist a a whole bunch of before, after around / wrap solutions, almost always unfortunately mentioning AO(P), and in far too many cases not taking care of the context or target which is essential to method modification.

The example I do provide uses a prototypal implementation of afterThrowing. Because JavaScript already features a standardized bind, I'm firmly convinced that Function.prototype is the right place as well for some other method-modifiers like before, after, around, afterThrowing and afterFinally.

// OP's example pseudo code
//
// functionName.before("try {")
//
// functionName.after("} catch(ex){
//   dostuff
// }")

function doStuffAfterThrowing(exception, originalArguments) {
  "use strict";
  var context = this;

  console.log('context : ', context);
  console.log('String(exception) : ', String(exception));
  console.log('originalArguments : ', originalArguments);

  return "safely handled exception";
}


function doFail() {
  throw (new ReferenceError);
}
function oneOutOfManyAjaxCallbacks(payload) {
  doFail();
}
var jsonData = {
  "foo": "foo",
  "bar": "bar"
};


var someModifiedAjaxCallback = oneOutOfManyAjaxCallbacks.afterThrowing(doStuffAfterThrowing, { x: 'y' });

// does fail controlled/handled.
console.log('someModifiedAjaxCallback(jsonData) : ', someModifiedAjaxCallback(jsonData));

// does fail "Uncaught".
console.log('oneOutOfManyAjaxCallbacks(jsonData) : ', oneOutOfManyAjaxCallbacks(jsonData));
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  (function (Function) {
    var
      isFunction = function (type) {
        return (
             (typeof type == "function")
          && (typeof type.call == "function")
          && (typeof type.apply == "function")
        );
      },
      getSanitizedTarget = function (target) {
        return ((target != null) && target) || null;
      }
    ;
    Function.prototype.afterThrowing = function (handler, target) { // afterThrowing
      target  = getSanitizedTarget(target);
      var proceed = this ;

      return (isFunction(handler) && isFunction(proceed) && function () {
        var ret, args = arguments;
        try {
          ret = proceed.apply(target, args);
        } catch (exc) {
          ret = handler.call(target, exc, args);
        //throw exc;
        }
        return ret;

      }) || proceed;
    };
  }(Function));
</script>

Having come that far one might also consider reading ...