JavaScript Performance Optimizations



JavaScript Performance Optimizations

0 0


js-performance-slides

A talk about JavaScript Performance Optimizations

On Github miki2826 / js-performance-slides

JavaScript Performance Optimizations

By Michael Dimenshtein

Why When What

Why

To achieve a balance between fast execution speed and small code size

When

After analysis! Don't jump to optimizations and don't over optimize

How

Strings, variables, functions...

Strings

Concat (str+) vs arr.join

                            //String concatenation
var myConcatString = "this is a string" +
"and I am another string" +
"together we make a bigger string";

//Array join
var myConcatString = ["this is a string",
"and I am another string",
"together we make a bigger string"].join();
						

Experiment results

Chrome, str+ vs. arr.join:

745M ops/sec vs. 21M ops/sec

FF, str+ vs. arr.join:

1Billion ops/sec vs. 7M ops/sec

Explanation

Depends on your browser:

Modern browsers heavily optimize the str+.

Variables

Global vs. local variable definition

                            //Global / outside reference
var i;
for (i=0; i<1000000; i++);

//Local function variable
function countMeLocal() {
 var i;
 for (i=0; i<1000000; i++);
}
countMeLocal(); 

Experiment results

Chrome, global vs local:

363 ops/sec vs.  1,008 ops/sec

FF, global vs local :

164 ops/sec vs.  1,572 ops/sec

Explanation

Scope chain lookup,

Global scope is a highly populated namespace,

Browser must distinguish between global variables and properties of objects that are in the current context. i.e alert()  and window.alert()

Functions

Defining class methods

                            //Define on instantiation
function MyClass() {
 // constructor body
 this.myFunc = function() {
  // do something
 };
}

//Define on the prototype
function MyClass() {
 // constructor body
}

MyClass.prototype.myFunc = function() {
 // do something
};
							

Experiment results

Instance Creation

Chrome, instance vs. prototype:

5M ops/sec vs.  70M ops/sec

FF, instance vs. prototype:

52M ops/sec vs.  518M ops/sec

Explanation

In the prototype approach, only a single instance of myFunc is created, compared to the second approach where myFunc is created for each instance. 

Experiment results

Function invocation

Chrome, instance vs. prototype:

75M ops/sec vs. 68M ops/sec

FF, instance vs. prototype:

1,015 Billion ops/sec vs.  1,015 Billion ops/sec

Explanation

Basically similar results.

Browsers heavily optimize the prototype chain lookup.

Functions

Access Instance variables declaration/initialization with value type 

                            //Define on instantiation
function MyClass() {
 // constructor body
 this.myNumber = 4;
 this.myBoolean = true;
 this.myString = 'what?!?!?';
 this.myArray = [];
}

//Define on the prototype
function MyClass() {
 // constructor body
 this.myArray = [];
}

MyClass.prototype.myNumber = 4;
MyClass.prototype.myBoolean = true;
MyClass.prototype.myString = 'what?!?!?';

Same Result

Closures

Invoke a function with closure vs. An inner function with no closure vs. a static reference to a function.

                            //Closure (referencing msg)
function tellTheWorld() {
 var msg = 'I am Iron Man';
 setTimeout(function() {
  alert(msg);
 }, 100);
}

//Inner function - no closure
function tellTheWorld() {
 setTimeout(function() {
  var msg = 'I am Iron Man';
  alert(msg);
 }, 100);
}

//Reuse a static function
function theMessage() {
 var msg = 'I am Iron Man';
 alert(msg);
}

function tellTheWorld() {
 setTimeout(theMessage, 100);
}

Experiment results

Closure

Chrome 295K ops/sec  

FF 69K ops/sec

Inner function

Chrome 297K ops/sec  

FF 70K ops/sec

Static function

Chrome 328K ops/sec  

FF 73K ops/sec

Explanation

Closure is slowest - adds another level to the scope (scope chain lookup is slower)

Inner function is slower - recreating the function 

Static function is fastest - referencing the same function

Closures

Invoke a function with closure vs. An inner function with no closure vs. a static reference to a function. Without setTimeout

                            function doSomeThing(func) {
 func();
}
function theMessage() {
 var msg = 'I am Iron Man';
 console.log(msg);
}
function MyTestClass() {
 //Closure (referencing msg)
 function tellTheWorldWithClosure() {
  var msg = 'I am Iron Man';
  doSomeThing(function () {
   console.log(msg);
  });
 }
 //Inner function - no closure
 function tellTheWorldWithInnerFunc() {
  doSomeThing(function () {
   var msg = 'I am Iron Man';
   console.log(msg);
  });
 }
 //Reuse a static function
 function tellTheWorldStatically() {
  doSomeThing(theMessage);
 }
 return {
  tellTheWorldWithClosure: tellTheWorldWithClosure,
  tellTheWorldWithInnerFunc: tellTheWorldWithInnerFunc,
  tellTheWorldStatically: tellTheWorldStatically
 }
}
var myFuncs = MyTestClass();

Beware of

eval, setTimeout, try-catch, a with statement

Thank You

JS Perf Links

http://jsperf.com/wj-concat-vs-join

http://jsperf.com/wj-define-class-method

http://jsperf.com/wj-invoke-function-on-instance-vs-on-prototype

http://jsperf.com/wj-access-variable-on-instance-vs-on-prototype

http://jsperf.com/wj-closure-vs-inner-func-vs-static-func

http://jsperf.com/ws-closure-vs-inner-vs-static-no-lookup

http://jsperf.com/wj-local-function-variable

http://jsperf.com/wj-local-function-variable2

JavaScript Performance Optimizations By Michael Dimenshtein