Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I use this simple time method to time intervals. It basically just consolidates some simple math.

/*time
**  dependencies - none
**  browser - unknown
**
*/
NS.time = (function () {
    var measurements = [];
    return function (control) {
        var index,
            intervals = [],
            time_current = new Date().getTime();
        if (control === 'start') {
            measurements = [];
            measurements.push(time_current);
            return;
        }
        if (control !== 'finish') {
            measurements.push(time_current);
            return;
        }
        if (control === 'finish') {
            measurements.push(time_current);
            index = measurements.length;
            while (index) {
                index--;
                intervals[index - 1] = (measurements[index] - measurements[index - 1]) + 'ms';
            }
            return intervals;
        }
    };
}());
share|improve this question
add comment

1 Answer 1

up vote 2 down vote accepted

Since start, middle and finish are pretty much "verbs", why not make them actions of the object time? With that, an API like this would do:

$.time.start();
$.time.middle();
$.time.finish();

Further, a developer might run multiple instances of a timer to track more than just one something. Maybe a developer would like to run one timer for a page load while another set of timers for image loading. Thus, it would be better if we created instances:

//returns an instance id'ed by "pageload"
//passing blank creates only one anonymous timer
var pageLoadTimer = $.time('pageload');

//methods
pageLoadTimer.start();
pageLoadTimer.middle();
pageLoadTimer.finish();

//or simply chain
$.time('pageload').start();

//if you lose reference because you are not on the same scope
//or forgot to make one 
//or didn't make one at all and relied on the globality of jQuery
//calling a timer of the same name returns an existing timer
$.time('pageload').middle();

Anyways, with that adapted code, a result would be (as verbose as I can):

$.time = (function () {

  //our timer cache
  var timers = {};

  //extract common code
  function getCurrentTimestamp() {
    return new Date().getTime();
  }

  //constructor to our instances
  //each with a name, time collection and difference collection
  function Timer(timerName) {
    this.name = timerName;
    this.times = [];
    this.perf = [];
    this.lastPerfIndex = 0;
  }

  //since the initialization has been done in the constructor
  //we remove it from start. but since start and middle does
  //the same thing, we merge it as "ping"
  Timer.prototype.ping = function () {
    this.times.push(getCurrentTimestamp());
    return this;
  };

  //calculate
  //a developer might want to get performance data
  //before actually finishing, thus the rename
  Timer.prototype.calculate = function () {

    //caching a few variables from the instance
    var perf = this.perf,
      times = this.times,
      timesLength = times.length, //getting n-1 length
      i = this.lastPerfIndex; //perfIndex explained further down

    //ping our last time check
    this.ping();

    //now a reverse loop would only make the code longer
    //a forward loop would make it much simpler
    while (i <= timesLength) {

      //now a developer might want to get performance data
      //but you would not want to calculate the entire set again
      //thus we store a last index, so the next call starts from here
      this.lastPerfIndex = i;

      //now since we are in order, use push instead
      //of manually jotting down the index
      perf.push(times[i + 1] - times[i]);
    }
    return perf;
  };

  //lets implement finish as a destroy function instead
  Timer.prototype.finish = function(){
    //remove this timer from cache
    delete timers[this.name];
    //return performance data
    return this.calculate;
  }


  return function (timerName) {
    if (timers[timerName]) {
      //if timer with name exists, return existing
      return timers[timerName];
    } else {
      //or cache and return a new one
      //creating a new one does not start it immediately
      //useful for stuff like preloading stuff or something
      return timers[timerName] = new Timer(timerName);
    }
  };
}());

In the end, usage might look like this:

//create a timer
$.timer('foo');

//aw snap! i forgot to reference, we can retrieve it
var foo = $.timer('foo').ping(); //lets start!

//some lines later, let's mark this period
$.timer('foo').ping(); //by retrieval
foo.ping();            //by reference "foo"

//let's get the performance array without killing this timer
var perfAfterTenKlines = foo.calculaate();

//let's get the performance array gain after 20 lines
//this time it calculates only data since last calculate
var perfAfterTwentyKlines = foo.calculate();

//ok we're done. lets get the final data and call it a day
var perfAfterOneMlines = foo.finish();
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.