【问题标题】:Javascript console output before and after method call with AOP使用 AOP 调用方法之前和之后的 Javascript 控制台输出
【发布时间】:2014-11-06 10:54:50
【问题描述】:

我想测量方法的计算时间。

一个不错的方法是 (How do you performance test JavaScript code?) 与 console.time('Function #1');console.timeEnd('Function #1');

我的想法是在生命周期方法中添加这些控制台输出。在这种情况下使用 SAPUI5 之类的 createContent:funtion(){}; 方法。

这应该可以通过 AOP 使用 before()after() 来减少时间计数。

您建议使用哪种 AOP 框架,以及如何在需要自动修改标识字符串 “Function #1” 的情况下实现它?

【问题讨论】:

    标签: javascript aop sapui5 function-composition modifier


    【解决方案1】:

    实际上,Javascript 中不需要切面,因为您可以随时更改任何对象的任何功能。 JavaScript 原型允许您在运行时操作对象的所有实例的方法实现。以下是您计划的两种方法。

    您可以使用通用包装函数:

    var measureId = 0;
    var fnMeasureFunction = function(fnToMeasure) {
      console.time('measure'+ measureId);
      fnToMeasure();
      console.timeEnd('measure'+ measureId);
      measureId++;
    }
    

    诚然,这需要您更改实际代码...

    对于静态函数或属于原型的函数,您也可以这样做。从外部像这样,无需对现有代码进行任何更改:

    // any static function
    var measureId = 0;
    var fnOriginalFunction = sap.ui.core.mvc.JSViewRenderer.render;
    sap.ui.core.mvc.JSViewRenderer.render = function() {
      console.time('measure'+ measureId);
      fnOriginalFunction.apply(this, arguments);
      console.timeEnd('measure'+ measureId);
      measureId++;
    }
    
    // any prototype function
    var fnOriginalFunction = sap.m.Button.prototype.ontouchstart;
    sap.m.Button.prototype.ontouchstart= function() {
      console.time('measure'+ measureId);
      fnOriginalFunction.apply(this, arguments);
      console.timeEnd('measure'+ measureId);
      measureId++;
    }
    

    【讨论】:

      【解决方案2】:

      这应该可以通过 AOP 使用 before() 和 after() 来减少时间计数。

      正如已经提到的,真的不需要真正的面向方面的编程 为了在 JavaScript 中解决此类任务。但是这种语言可能值得一些更标准化的 方法修饰符 除了已经存在的bind 方法。

      请查看我最近关于此问题的 2 个帖子:

      ...以及如何实现需要自动修改识别字符串“Function #1”?

      不需要,因为控制台的time / timeEnd 功能只需要有 测量时间的相同入口和出口点(如秒表的开始/停止触发器)。 因此,与当前正在运行/测量的函数/方法的引用完全一致。

      为了解决给定的任务,我只建议around 而不是beforeafter 前者产生的开销更少。下一个代码块示例性地显示了 可能的原型实现。它也是后面示例的基础 这最终可能会解决 OP 的任务。

      (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.around = function (handler, target) { // [around]
          target  = getSanitizedTarget(target);
      
          var proceed = this;
          return (isFunction(handler) && isFunction(proceed) && function () {
      
            return handler.call(target, proceed, handler, arguments);
      
          }) || proceed;
        };
      }(Function));
      

      下一个示例考虑到 method-modification 本质上依赖于 绑定到对象的功能。它不仅仅是函数包装。为了 为了不丢失方法正在运行的 contextcontext 必须被委派/ 在所有操作中作为target 传递。

      为此,示例不会修改calculate,因为它没有绑定到对象 但它改为修改trigger

      var testObject = {
      
        calculate: function (hugeInteger) {
          var
            i = hugeInteger,
            k = 0
          ;
          while (i--) {
            k++;
          }
          return k;
        },
        trigger: function (hugeInteger) {
          this.result = this.calculate(hugeInteger);
        },
        result: -1
      };
      
      console.log("testObject.result : ", testObject.result);
      
      console.log("testObject.trigger(Math.pow(2, 26)) : ", testObject.trigger(Math.pow(2, 26))); // takes some time.
      console.log("testObject.result : ", testObject.result);
      
      console.log("testObject.someTrigger(0) : ", testObject.trigger(0)); // logs immediately after.
      console.log("testObject.result : ", testObject.result);
      
      
      testObject.trigger = testObject.trigger.around(function (proceed, interceptor, args) {
      
        // before:
        console.time(proceed);
      
        // proceed:
        proceed.apply(this, args);
      
        // after:
        console.timeEnd(proceed);
      
      }, testObject); // omitting the 2nd argument - the [target] object - might break code that did work before.
      
      
      console.log("testObject.trigger(Math.pow(2, 26)) : ", testObject.trigger(Math.pow(2, 26)));
      console.log("testObject.result : ", testObject.result);
      .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.around = function (handler, target) { // [around]
            target  = getSanitizedTarget(target);
      
            var proceed = this;
            return (isFunction(handler) && isFunction(proceed) && function () {
      
              return handler.call(target, proceed, handler, arguments);
      
            }) || proceed;
          };
        }(Function));
      </script>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-04
        • 2023-02-07
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        相关资源
        最近更新 更多