Optimization Monday — Part VIII: use function pointers

Optimization Monday 3 Comments »

Let us assume that you have a function which will execute different code based on conditions which do not change during runtime (e.g. the rendering engine of the user agent).

function doStuff(){
  if(userAgent == "internetexplorer"){
    // ...
  }else if(userAgent == "firefox"){
    // ..
  }else if(userAgent == "webkit"){
    // ..
  }else if(userAgent == "opera"){
    // ..
  }else{
    // ..
  }
}

Each time the function is called the string comparisons have to be done, even if the value for userAgent will not change at all.

To optimize this situation assign the actual function code to a variable named doStuff:

 
if(userAgent == "internetexplorer"){
  doStuff = function(){ /* .. */ };
}else if(userAgent == "firefox"){
  doStuff = function(){ /* .. */ };
}else if(userAgent == "webkit"){
  doStuff = function(){ /* .. */ };
}else if(userAgent == "opera"){
  doStuff = function(){ /* .. */ };
}else{
  doStuff = function(){ /* .. */ };
}
 

After this no more string comparisons are needed. :-)

Optimization Monday — Part VII: set CSS in one step

Optimization Monday 2 Comments »

Often you need to set just a single CSS attribute in your web application. You will usually do this by applying a value to the specified style attribute.

myElement.style.color = 'red';

Sometimes you will have to set a number of attribute values at once. For example if you have just created an element and can not assign a CSS class, because all attributes depend on specified conditions. In this case it is significant faster to set a value for the whole style attribute instead of setting each CSS attribute.

This five assignments

var myDiv = document.createElement('div');
myDiv.style.backgroundColor = 'blue';
myDiv.style.border = 'solid 4px red';
myDiv.style.fontFamily = 'Helvetica, Arial';
myDiv.style.width = '400px';
myDiv.style.height = '100px';
 

can be combined into one

var myDiv = document.createElement('div');
myDiv.setAttribute('style', 'background-color:blue;border:solid 4px red;font-family:Helvetica, Arial;width:400px;height:100px;');

If you are dealing with dynamically created elements, be sure to read part three of this series. ;-)

Optimization Monday — Part VI: expression order

Optimization Monday No Comments »

JavaScript has the nice ability to stop evaluating expressions in a condition as soon as the condition result is final.

function test(){
  alert("this message will never be shown!");
  return true;
}
 
if( true || test() ){
  // ..
}
 
if( false && test() ){
 // ..
}

Since expressions are evaluated from left to right we have the following possibilities to optimize the expression order:

  1. align less complex expressions left
  2. for disjunctions: put the expression which will most likely be true to the left
  3. for conjunctions: put the expression which will most likely be false to the left
  4. group depending expressions

Of course the rules also apply to nested expressions.

This example

if(
  (
    (complexCalculation() < 42) &&
    (
      (userAgentVersion < 7) &&
      activexDisabled() &&
      (getUserAgent() == "Internet Explorer")
    )
  ) || (
    (value > 0)
  )
){
 // ..
}

can be optimized to

if(
  (value > 0) || (
    (
      (getUserAgent() == "Internet Explorer") &&
      (userAgentVersion < 7) &&
      activexDisabled()
    ) &&
    (complexCalculation() < 42)
  )
){
 // ..
}

Optimization Monday — Part V: initilize variables and assign values in one step

Optimization Monday No Comments »

You can save execution time by assigning values to variables at the same time there are initilized.

var myString;
var myArray;
 
myString = 'lorem ';
myString += 'ipsum';
 
myArray = new Array();
myArray.push('foo');
myArray.push('bar');

You can also save a little amount of time by avoiding concating strings via the += operator.

var myString = 'lorem ipsum';
var myArray = ['foo', 'bar'];

Optimization Monday — Part IV: use object literals

Optimization Monday No Comments »

Use object literals to initialize or set your object attributes.

Instead of

Initech.legalForm = 'corporation';
Initech.workEnvironment = 'cubeFarm';
Initech.coffee = 'lousy';

write

Initech = {
  legalForm : 'corporation',
  workEnvironment : 'cubeFarm',
  coffee : 'lousy'
};

Optimization Monday — Part III: append elements after doing all modifications

Optimization Monday No Comments »

Todays hint is: append newly created HTML element objecs to the document object first when all modifications to them are done. This can lead to great performance boots, because style or behavior changes (during the creation process) do not have to be applied by the browser.

So to improve this code snippet

var blockElement = document.createElement('div');
var paragraphElement = document.createElement('p');
var boldElement = document.createElement('b');
 
document.body.appendChild(blockElement);
 
blockElement.appendChild(paragraphElement);
blockElement.firstChild.appendChild(boldElement);
blockElement.firstChild.firstChild.innerHTML = 'test paragraph';
blockElement.className = 'myClass';

apply the newly created element at the end.

var blockElement = document.createElement('div');
var paragraphElement = document.createElement('p');
var boldElement = document.createElement('b');
 
blockElement.appendChild(paragraphElement);
blockElement.firstChild.appendChild(boldElement);
blockElement.firstChild.firstChild.innerHTML = 'test paragraph';
blockElement.className = 'myClass';
 
document.body.appendChild(blockElement);

If the style settings described in myClass are applied to blockElement's child nodes, they have to be rendered again — even if they were just added to the document.

Optimization Monday — Part II: function handles

Optimization Monday No Comments »

This entry is a little late, due my holiday (prearrangement), but nevertheless here is the hint for August 2007: use function handles instead of strings for window.setTimeout() and window.setInterval().
By using function handles you avoid an unnecessary evaluation of a string.

So instead of

var myHandle = window.setTimeout("doStuff()", 100);

use

var myHandle = window.setTimeout(doStuff, 100);

Of course this hint is only useful if want to call a parameter less function — which should be no problem in connection with window.setTimeout() or window.setInterval(). ;-)

Update:
Actually, there is a way for having a function call with parameters. All we need is a wrapper function and a little bit closures magic:

function wrapperFunc(firstParam, secondParam){
  return (function(){
    doStuff(firstParam, secondParam);
  });
}
 
var myWrapper = wrapperFunc('foo', 'bar');
var myHandle = window.setTimeout(myWrapper, 100);

The real trick is that the myWrapper variable contains an anonymous function together with two variables, which were set when wrapperFunc() was called. By applying this variable to windows.setTimeout() method, the anonymous function (containing the call of doStuff()) will be executed after the given timeout.

Optimization Monday — Part I: Prevent lookups

Optimization Monday No Comments »

For the most of us, Monday is the beginning of a new working week. Often you feel a bit slow and sleepy (especially if you have a case of Mondays ;-) ).
But having a slow developer in front of the screen does not mean that your code has to be slow as well. So, I started the series Optimization Monday which will include one small, but effective hint for optimizing and speeding up your JavaScript code on each month's first Monday.

Today's hint is: prevent lookups.
Every word in your object chain has to be found in the interpreter's lookup table. You can shorten the chain by using a local variable which holds a reference to your target.

So, instead of

for(i=0; i<100; i++){
  Initech.Web.Framework.WebsuiteObjects.Counter.increase(i);
}

write this:

var incr = Initech.Web.Framework.WebsuiteObjects.Counter.increase;
for(i=0; i<100; i++){
  incr(i);
}

If you are using DOM functions, the advantage of using a reference will be even greater.

Slow:

document.body.childNodes[8].firstChild.childNodes[3].nodeValue = 'foo';
document.body.childNodes[8].firstChild.childNodes[6].nodeValue = 'bar';
document.body.childNodes[8].firstChild.childNodes[8].nodeValue = '42';

Faster:

var elem = document.body.childNodes[8].firstChild;
elem.childNodes[3].nodeValue = 'foo';
elem.childNodes[6].nodeValue = 'bar';
elem.childNodes[8].nodeValue = '42';

WordPress Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in