1

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.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • 2
    Why don't you just create your own function that you use to do all your ajax calls and have all your common code in there including a `try, catch`? – David Sherret Jul 23 '14 at 13:26
  • 4
    Sounds like a bad design problem. Common code should have been refactored out. – epascarello Jul 23 '14 at 13:27
  • I don't know anything about AOP, but JavaScript is super flexible and can be manipulated on the fly. That said, the above commenters are correct--this is a code design problem which should be corrected with an abstraction. – JAAulde Jul 23 '14 at 13:32
  • Well not really, I am working on salesforce and the ajax methods are given by some weird JSP code, not that I designed it that way. I can then only wrap those methods which is what I have been doing – Bryan Arbelo - MaG3Stican Jul 23 '14 at 13:32
  • Post an example couple of methods – Mardoxx Jul 23 '14 at 13:38
  • Regarding the `AOP` tag, wrapping and reassigning already declared functionality (be it functions or methods) misses any aspect of _AOP_. Any language which wants to qualify for the latter has to provide abstraction levels for at least `Joinpoint`, `Advice` and `Aspect`. The use case described by the OP should be referred to as method modification, and JavaScript of cause is well suited for this scenario and could easily provide a complete `target`/`context` aware toolset of method modifiers like `around`, `before`, `after`, `afterThrowing` and `afterFinally` via `Function.prototype`. – Peter Seliger Sep 14 '22 at 17:29

4 Answers4

3

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);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • uh, that's just what your `functionName.before` and `.after` were also doing. You can of course easily make a non-prototype function of it. – Bergi Jul 23 '14 at 14:02
0

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.

André Pavan
  • 101
  • 5
0

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
  }
}
k1r0s
  • 359
  • 3
  • 14
0

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

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37