OK, so I have to look into a knockout binding to figure out why it’s pausing at times (taking too long). So, sometimes I like to instrument routines whereby I essentially log the time the routine took to execute so I can find the culprit more quickly. In javascript (and leveraging the ever-awesome underscore library), this is a simple task. We can rip through all the functions in the object and wrap them so that we can intercept those calls. Within the interception workflow, we log the start time, run the original call, then calculate the difference between start and now and hand that back to the consumer. Here’s the entire simple implementation of this instrumentation:
var MyCompany = (function (kernel, $) {
var items = [];
var public = {};
public.start = function () {
items.push(new Date());
};
public.stop = function () {
var now = new Date();
var item = items.pop();
return now – item;
};
var wrap = function (context, original, handler, funcName) {
return function () {
public.start();
original.apply(context, arguments);
handler(public.stop(), funcName);
};
};
public.instrument = function (target, handler, suppliedFunctionName) {
handler = handler || function (funcName, invocationTime) {
console.log(‘Time to execute “‘ + funcName + ‘”: ‘ + invocationTime);
};
if (_.isFunction(target)) {
return wrap(target, target, handler, suppliedFunctionName || ‘ (Not specified)’);
} else {
_.each(_.functions(target), function (funcName) {
target[funcName] = wrap(target, target[funcName], handler, funcName);
});
}
};
kernel.instrumentation = public;
return kernel;
})(MyCompany || {}, jQuery);
Here’s a usage example. First, we’ll create a couple helpers for writing to the window and simulating long-running code:
var writeIt = function(message){
document.write(message + '<br/>');
};
var sleep = function(milliSeconds){
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + milliSeconds);
}
Then here’s our object we’ll instrument shortly:
var person = {
firstName: ‘jason’,
lastName: ‘harper’,
sayName: function(){
sleep(1000);
writeIt(this.firstName + ‘ ‘ + this.lastName);
}
};
Figure out what you want to do with the instrumentation informs you a method finishes:
var callback = function(invocationTime, funcName){
writeIt(‘Time to execute “‘ + funcName + ‘”: ‘ + invocationTime);
};
Now go ahead and instrument your object and call the method as normal:
MyCompany.instrumentation.instrument(person,callback );
person.sayName();
You can also instrument just a function:
var sayHello = function(){
sleep(400);
writeIt(‘uh…hello?’);
};
sayHello = MyCompany.instrumentation.instrument(sayHello,callback, ‘sayHello’ );
sayHello();