Question

Quelle bibliothèque AOP Javascript utilisez-vous et quelles sont ses fonctionnalités clés?

Était-ce utile?

La solution

Voici ce que j'ai trouvé jusqu'à présent:

  • implémentation de dotvoid , syntaxe pure , agréable à utiliser, cet article est une bonne introduction sur pourquoi / comment utiliser le code donné, supporte les introductions, mais est bogué,
  • Dojo a ce qui semble être une bonne implémentation intégrée dans dojox , ici est une belle introduction sur la façon dont pour l'utiliser,
  • il existe un plug-in pour jQuery, jquery-aop , avec une syntaxe plus grossière. , passage d'objets et de méthodes dans un objet javascript,
  • AspectJS avec une syntaxe encore plus rugueuse (nécessité de transmettre le type de pointcut sous forme d'arguments à une seule méthode)

Comme je l'ai dit, le code de dotvoid ne fonctionnait pas. J'ai corrigé un peu et obtenu quelque chose qui semble mieux fonctionner:

InvalidAspect = new Error("Missing a valid aspect. Aspect is not a function.");
InvalidObject = new Error("Missing valid object or an array of valid objects.");
InvalidMethod = new Error("Missing valid method to apply aspect on.");

function doBefore(beforeFunc,func){
    return function(){
        beforeFunc.apply(this,arguments);
        return func.apply(this,arguments);
    };  
}

function doAfter(func, afterFunc){
    return function(){
        var res = func.apply(this,arguments);
        afterFunc.apply(this,arguments);
        return res;   
    };
}

Aspects = function(){};
Aspects.prototype={
    _addIntroduction : function(intro, obj){
         for (var m in intro.prototype) {
              obj.prototype[m] = intro.prototype[m];
            }
        },

    addIntroduction : function(aspect, objs){
        var oType = typeof(objs);

        if (typeof(aspect) != 'function')
        throw(InvalidAspect);

        if (oType == 'function'){
            this._addIntroduction(aspect, objs);
        }
        else if (oType == 'object'){
            for (var n = 0; n < objs.length; n++){
                this._addIntroduction(aspect, objs[n]);
            }
        }
        else{
            throw InvalidObject;
        }
    },

    addBefore : function(aspect, obj, funcs){
          var fType = typeof(funcs);

          if (typeof(aspect) != 'function')
            throw(InvalidAspect);

          if (fType != 'object')
            funcs = Array(funcs);

          for (var n = 0; n < funcs.length; n++){
            var fName = funcs[n];
            var old = obj.prototype[fName];

            if (!old)
              throw InvalidMethod;

            var res = doBefore(aspect,old)
            obj.prototype[fName] = res;
        }
    },

    addAfter : function(aspect, obj, funcs) {
          if (typeof(aspect) != 'function')
            throw InvalidAspect;

          if (typeof(funcs) != 'object')
            funcs = Array(funcs);

          for (var n = 0; n < funcs.length; n++)
          {
            var fName = funcs[n];
            var old = obj.prototype[fName];

            if (!old)
              throw InvalidMethod;

            var res = doAfter(old,aspect);
            obj.prototype[fName] = res;
          }
        },

    addAround : function(aspect, obj, funcs){
          if (typeof(aspect) != 'function')
            throw InvalidAspect;

          if (typeof(funcs) != 'object')
            funcs = Array(funcs);

          for (var n = 0; n < funcs.length; n++)
          {
            var fName = funcs[n];
            var old = obj.prototype[fName];
            if (!old)
              throw InvalidMethod;

            var res = aspect(old);
            obj.prototype[fName] = res;
          }

          return true;
        }
}

Autres conseils

Avez-vous vu meld.js et aop.js depuis https://github.com/cujojs ?

SpringSource fournit ici la fonctionnalité AOP, ainsi que de nombreuses autres choses utiles pour les programmeurs Javascript avancés.

Clause de non-responsabilité : je travaille pour SpringSource.

Sur la base de la solution dotvoid, j’ai créé ma propre version de JS AOP pour les besoins de mes propres projets. Je veux fondamentalement minimiser les coûts de configuration de l’aspect, j’ai donc ajouté la fonctionnalité de configuration de l’aspect à Function.prototype.

Function.prototype.applyBefore = function (aspect, targetFuncNames) {
....
}

Je dois également prendre en charge les rappels aync, tels que l'authentification et l'autorisation pour certaines méthodes. Par exemple:

var authenticateAspect = function (error, success, context, args) {
    logger.log('authenticate (applyBefore async) aspect is being called');
    var request = $.ajax({
        url: "http://localhost/BlogWeb/api/user/authenticate",
        type: "GET",
        data: { username:'jeff', pwd:'jeff' },
        success: function (data) {
            if (data) {
                success();
            } else {
                error();
            }
        },
        error: error
    });
    return request;
};

Person.applyBefore(authenticateAspect, 'sendNotification');

var p1 = new Person();

p1.sendNotification();

Pour implémenter cela, je dois exécuter la sécurité et continuer en cas de succès ou arrêter l'exécution en cas d'échec.

var invalidAspect = new Error("Missing a valid aspect. Aspect is not a function."),
    invalidMethod = new Error("Missing valid method to apply aspect on.");

///Parameters: aspect - defines the methods we want call before or/and 
///             after each method call ob target obejct
///            targetFuncNames - target function names to apply aspects
///Return: it should return a new object with all aspects setup on target object
Function.prototype.applyBefore = function (aspect, targetFuncNames) {
    if (typeof (aspect) != 'function')
        throw invalidAspect;

    if (typeof (targetFuncNames) != 'object')
        targetFuncNames = Array(targetFuncNames);

    var targetObj = this;
    //error handling function

    // Copy the properties over onto the new prototype
    for (var i = 0, len = targetFuncNames.length; i < len; i++) {
        var funcName = targetFuncNames[i];
        var targetFunc = targetObj.prototype[funcName];

        if (!targetFunc)
            throw invalidMethod;


        targetObj.prototype[funcName] = function () {
            var self = this, args = arguments;
            var success = function() {
                return targetFunc.apply(self, args);
            };
            var error = function () {
                logger.log('applyBefore aspect failed to pass');
                //log the error and throw new error
                throw new Error('applyBefore aspect failed to pass');
            };

            var aspectResult = aspect.apply(null, Array.prototype.concat([error, success, self], args));
            return aspectResult;
        };
    }
};

La mise en œuvre complète est disponible à l'adresse http://www.jeffjin.net/aop-with- javascript

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top