问题
I would like to measure the computing time of methods.
A nice way is (How do you performance test JavaScript code?) with console.time('Function #1');
and console.timeEnd('Function #1');
My idea is to add these console outputs on lifecycle-methods. In this case using SAPUI5 like createContent:funtion(){};
methods.
This should be possible with AOP using before()
and after()
to runt the time counting.
Which AOP framework would you suggest and how to implement it with the need of modifying the identification string "Function #1" automatically?
回答1:
There actually is no need for aspects in Javascript since you can change any function of any object at any time. JavaScript prototypes allows you to manipulate method implementations of all instances of an object at runtime. Here are two approaches for what you plan.
You could use a generic wrapper function:
var measureId = 0;
var fnMeasureFunction = function(fnToMeasure) {
console.time('measure'+ measureId);
fnToMeasure();
console.timeEnd('measure'+ measureId);
measureId++;
}
Admittedly that requires you to change your actual code...
For static functions or functions that belong to a prototype you could also do sth. like this from the outside without the need of any change to your existing code:
// 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:
This should be possible with AOP using before() and after() to runt the time counting.
As it already got mentioned, one really is not in need of real Aspect-oriented Programming
in order to solve such tasks in JavaScript. But this language might deserve some more standardized
method-modifiers in addition to the already existing bind
method.
Please check back with my 2 most recent posts on this matter:
- sandwich pattern in javascript code
- Can you alter a Javascript function after declaring it?
... and how to implement it with the need of modifying the identification string "Function #1" automatically?
One does not need to since the console's time
/ timeEnd
functionality only has to have
identical entry and exit points for measuring time (like the start/stop trigger of a stopwatch).
So one gets along with exactly the reference of the function/method one is currently running/measuring.
In order to solve the given task I will suggest around
only instead of both before
and
after
for the former generates less overhead. The next code block exemplarily shows a
possible prototypal implementation. It also is the base for the afterwards following example
that finally might solve the OP's task.
(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));
The next example takes into account that method-modification essentially relies on
functionality that is bound to an object. It is not just function wrapping. In order
to not loose the context a method is operating on, context has to be delegated /
passed around as target
throughout all operations.
For this the example does not modify calculate
since it is not bound to an object
but it modifies trigger
instead.
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);
来源:https://stackoverflow.com/questions/26777671/javascript-console-output-before-and-after-method-call-with-aop