I was doing some research on script loading speed tests. Each script load required the page to be refreshed, making it difficult to log the time to Firebug and get an average. It was certainly too much trouble to write some PHP scripts and connect to a database; and possibly even worse would be having to pull out a pencil and paper and write the times down. I’m not even sure I have a pencil.

The obvious solution was to write the data to a cookie. I also thought the solution was universal enough to blog about so others could use it too.

The first thing we need is a timer. Firebug has a timer, but it doesn’t return the results so that they can be saved. The timer will be a singleton since we will only need one instance holding all of the data, and it will be a global object so we can access it anywhere. The code is quite simple:

dojo.provide("mikespace.timer");
timer = {
	_map:{},
	start: function(msg){
		this._map[msg] = new Date().getTime();
	},
	end:   function(msg){
		this._map[msg] = new Date().getTime() - this._map[msg];
		return this._map[msg];
	},
	show: function(msg){
		console.log( "---------> " + msg + ": " + this._map[msg]);	
	}
};
// usage:
// timer.start("first test");
// var time = timer.end("first test);

This code is in a directory (or package) named mikespace. As you can see, the times are set and retrieved based on the label parameter, and stored in a hash map. There’s also a show() method – although I’m not going to use it here, I use this often. When conducting speed tests in an application, the timers are usually sprinkled everywhere throughout the code and show in various places in the log messages. By just calling timer.end() I store the time, and after all of the tests have been run, I call timer.show(msg) for each test, and log them all in one place.

Next we need our cookie aggregator. This too could be a singleton, but after considering that there could be multiple tests in a page, I decided to make it a PODO (Plain Old Dojo Object). Here is the full code for cookieData, and I’ll explain after:

dojo.provide("mikespace.cookieData");
dojo.require("dojo.cookie");
	
dojo.declare("mikespace.cookieData", null, {
	cookieName:"scriptTests",
	expires:1,
	testData:[],
	constructor: function(args){
		for (var nm in args){
			this[nm] = args[nm];	
		}
	},
	loadData: function(){
		this.cookie = dojo.cookie(this.cookieName);
		if(this.cookie){
			this.testData = dojo.fromJson(dojo.cookie(this.cookieName));
		}
	},
	getData: function(){
		return this.testData;
	},
	showData: function(){
		console.log("Test Name:", this.cookieName);
		
		var data = this.getData();
		var avr = 0;
		var amt = 0;
		dojo.forEach(data, function(d, i){
			console.log(i, "test:", d);
			avr+=d;
			amt++;
		});
		
		console.log("Average:", Math.ceil(avr/amt));
	},
	saveData: function(data){
		this.testData.push(data);
		 dojo.cookie(
			this.cookieName, 
			dojo.toJson(this.testData),
			{ expires: this.expires }
		);
	},
	clearData: function(){
		dojo.cookie(
			this.cookieName, 
			dojo.toJson([]), 
			{ expires: this.expires }
		);
	},
	deleteCookie: function(){
		dojo.cookie(this.cookieName, null, { expires: -1 });
	}
});

I’m utilizing dojo.cookie, so it is required. I declare mikespace.cookieData, and I’m not extending anything (like dijit._Widget), so the second parameter is null. Because I’m not using dijit._Widget, I’m mixing in the arguments object myself in the constructor. I then instantiate a few variables. expires is set to one day, which could be left as-is if you don’t want to leave the cookie hanging around on your system when your done. Or set it to an arbitrarily large number and use the deleteCookie() method.

The rest of the code should be quite easy to understand. in loadData() we check if the cookie exists, and if not, we create one with new data. In showData() I log each test and number it, so I can easily see how many tests I’ve run, and then I show the average. The showData() method could obviously be any kind of code, including parsing tests within tests. And semantically, it probably should be outside of this cookieData; if we wanted to just use it as a getter and setter and then create another object for displaying the results.

Now we’ll create our HTML page where we will run the tests. After including the Dojo script tag, and the djConfig, I register the mikespace namespace, and then require the files:

dojo.registerModulePath("mikespace", "../../tests/mikespace");
dojo.require("mikespace.timer");
dojo.require("mikespace.cookieData");

Now we’ll build our test. The test I’m conducting is how long it takes to load a script, and I chose dojox.data.jsonPathStore, because it’s nice and big and has a few dependencies. I modified the script to call the end of the test, after it loaded it’s dependent scripts:

...
dojo.require("dojo.date.stamp");

if(window.endTest){
	window.endTest();
}
...

And our test functions:

startTest = function(){
	timer.start("script loaded");
}
	
endTest = function(){
	var time = timer.end("script loaded");
	var testName = "dojox.data.jsonPathStore Load";
		
	var c = new mikespace.cookieData({cookieName:testName});
	//c.clearData();
	c.loadData();
	c.saveData(time);
	c.showData();
}

When endTest() is called, the cookieData object is created and the test data is saved and logged. Since the timer has already ended, the amount of time it takes to create this object is not factored into the results. If I want to start the test over, I uncomment c.cleardata() and refresh the page.

Finally, to launch our test, start the timer and load the script:

startTest();
	
dojo.require("dojox.data.jsonPathStore");

Refresh the page ten times and you have a legitimate average of how long it takes to load the script.

cookietestdataresults.png

And there you have a quick and dirty method for logging tests that involve page refreshes. This example could be taken even farther, enclosing the startTest() and endTest() in its own PODO which requires the timer and cookieData. Then it’s a simple matter of dropping in the one require to conduct some quick tests.