JavaScript performance
Sebastian Poręba
7th December 2011
Sebastian Poręba
7th December 2011
console.log('Hello le world');
#include <iostream>
using namespace std;
int main() {
cout << "Hello le world" << endl;
return 0;
}
var x = 1; // <-- perfect
x = 1; // <-- still works
x = 1 // <-- wtf JS?
var x = 1;
// not eqivalent to
x = 1;
var x = 1; // local
x = 1; // global: window.x
return
{
foo: "bar"
}
return {
foo: "bar"
}
fn("foo"); // fast
myObj.atr.atr.atr.fn("goo"); // 30-70% slower
http://jsperf.com/references
var tmpFn = myObj.atr.atr.atr.fn;
for(var i = 0; i < 1000; i++) {
tmpFn("goo");
}
for(var i = 0, tmpObj; i < myObj.length; i++) {
tmpObj = myObj[i].atr.atr.atr;
tmpObj.tmpFn1("goo");
tmpObj.tmpFn2("foo");
tmpObj.tmpFn3("moo");
}
function add(num1, num2){
return num1 + num2;
}
var result = add(5, 10);
(function() {
function add(num1, num2){
return num1 + num2;
}
var result = add(5, 10);
}())
for(var i = 0; i < 1000; i++) {
element.innerHTML += " num " + i;
}
for(var i = 0, txt = ""; i < 1000; i++) {
txt += " num " + i;
}
element.innerHTML = txt;
function toggleBox(id) {
var element = document.getElementById(id);
if(element.style.display === "block") {
element.style.display = "none";
} else {
element.style.display = "block";
}
}
var memoizedDom = {};
var toggleBox = function(id) {
if(memoizedDom[id] === undefined) {
memoizedDom[id] = document.getElementById(id);
}
var element = memoizedDom[id];
if(element.style.display === "block") {
element.style.display = "none";
} else {
element.style.display = "block";
}
};
var toggleBox = (function() {
var memoizedDom = {};
return function(id) {
if(memoizedDom[id] === undefined) {
memoizedDom[id] = document.getElementById(id);
}
var element = memoizedDom[id];
if(element.style.display === "block") {
element.style.display = "none";
} else {
element.style.display = "block";
}
};
})();
$('.myClass').css("color", "pink");
$('.myClass').css("border", "3px solid even-pinker");
$('.myClass').show();
$('.myClass').onclick(function() {
alert("omg I'm so awesome programmer!");
});
$$ = (function() {
var memoizedDom = {};
return function(selector) {
if(memoizedDom[selector] === undefined) {
memoizedDom[selector] = $(selector);
}
return memoizedDom[selector];
};
})();
JSPerf - even faster memoization
var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // another reflow and a repaint
bstyle.color = "blue"; // repaint only, no dimensions changed
bstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));
function gc1() {
var x = 1; // gc
var y = 2; // gc
return 3;
}
function gc2() {
var x = 1; // gc
var y = 2; // immutable - no reference, gc
return {a: y};
}
function gc3() {
var x = 1; // gc
var y = [1,2,3]; // mutable - reference, no gc
return {a: y};
}
function gc4() {
var x = 1; // gc
var y = function() {return 5;}; // reference, no gc
return {a: y};
}
function gc5() {
var x = 1; // reference, no gc
var y = function() {return x;}; // reference, no gc
return {a: y};
}
function gc6() {
var x = 1; // eval, no gc
var y = function(c) {return eval(c);}; // reference, no gc
return {a: y};
}
var closure; function BigObject() { // return some big object}
var Foo = function() {};
Foo.prototype.setParentClass = function(parent) {
this.parentClass = parent;
}
var Bar = function() {
this.x = BigObject(); // x is not used in Foo
this.y = 2; // but y is
this.obj = new Foo();
this.obj.setParentClass(this);
};
function test_gc() {
var b = new Bar();
closure = b.obj;
}
Uses precise garbage collection - knows exactly where all the pointers are
Conservative garbage collector - any data may be a pointer. In some cases it leads to false positives.
function a(x,y) {
return 2*x+y;
}
function b(x,y) {
return a(x,y) + a(y,x);
}
function c(x,y) {
return Math.max(
b(x,y), b(y,x), 0
);
}
PYTHON = python
CALCDEPS = ~/closure/closure-library-read-only/closure/bin/calcdeps.py
CLOSURECOMPILER = ~/closure/compiler.jar
all:
$(PYTHON) $(CALCDEPS) -p src -i src/init.js
-o compiled -c $(CLOSURECOMPILER) > scripts/ai-bot-compiled.js
var foo = function(bar) {
if(bar == ('baz').length) {
return "\"" + '\'';
} else {
return 10000;
}
}
}
After compilation:
var foo=function(bar){
if(bar=="baz".length)return'"'+"'";
else return 1E4
};
var foo = function(bar) {
if(bar == ('baz').length) {
return "\"" + '\'';
} else {
return 10000;
}
}
}
After compilation:
var foo=function(a){return a==3?"\"'":1E4};
var foo = function(bar) {
if(bar == ('baz').length) {
return "\"" + '\'';
} else {
return 10000;
}
}
}
After compilation:
var COST_PER_VALUE_MENU_ITEM = 0.99;
var SALES_TAX = .05;
var DECATHLON_COST = 10 * (1 + SALES_TAX) * COST_PER_VALUE_MENU_ITEM;
var a = function() { return 1; };
var b = function(f) { f(); return 42; };
var c = function() { return b(a) * SALES_TAX; };
var d = function(n) { return (n > 0) ? a() : n * d(n - 1); };
var e = function() { return [b, c].length; };
console.log(e());
var SALES_TAX = .05;
var a = function() { return 1; };
var b = function(f) { f(); return 42; };
var c = function() { return b(a) * SALES_TAX; };
var e = function() { return [b, c].length; };
console.log(e());
final result:
console.log(2);