Code This, Not That

Javascript & JQuery Edition

Zachary Berry / @zachberry

About Me

  • Developer at Learning Systems & Technologies at UCF
  • 2004-2011: Flash & Flex developer
  • Now: HTML5, JS, etc

Performance

Keep on top of things

Don't Code This



						

Code That



						

Not only bug-fixes, but free performance increases...

Add this to your toolkit:

jsperf.com

http://jsperf.com

Keep on top of things

JSPerf results (Chrome 27):
Find in 1.4.2: 74,057 ops/sec
Find in 1.8.2: 127,227 ops/sec
Find in 1.9.0: 222,108 ops/sec

3x FASTER

Put that ish at the bottom

Don't Code This


<head>
	<script>
		$(document).ready(function() {
			doStuff();
		});
	</script>
</head>
						

Code That


<body>
	...
	<script>
		doStuff();
	</script>
</body>
						

JQuery Chaining & Caching

Don't Code This


$('.button').css('opacity', 0.5);
$('.button').css('padding', '20px');
$('.button').addClass('selected');
						

Code That


$('.button')
	.css('opacity', 0.5)
	.css('padding', '20px')
	.addClass('selected');
//OR, store it in a variable:
var $button = $('.button');
						

JQuery Caching & Chaining

JSPerf results (Chrome 27):
No Caching: 20,479 ops/sec
Caching:    24,518 ops/sec

A little bit faster

Select your selectors carefully

(An example)

Don't Code This


var $inputs = $('div:input');
						

Code That


var $inputs = $('div').filter(':input');
						

Q: How can hell can I keep track of all these jQuery selector performance tips?

Select your selectors carefully

A: Don't! Just check the jQuery documentation, jsperf tests to see if your selector might be improved

Because :input is a jQuery extension and not part of the CSS specification, queries using :input cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :input to select elements, first select the elements using a pure CSS selector, then use .filter(":input").

Don't create functions in a loop

No clever title this time

Don't code this


for(var i = 0, len = arr.length; i < len; i++) {
	arr[i].on('click', function(event) { /*...*/ });
}
						

Code that


var clickListener = function(event) { /*...*/ };
for(var i = 0, len = arr.length; i < len; i++) {
	arr[i].on('click', clickListener);
}
						

Protip: JS linter will point this mistake out to you.

Add this to your toolkit:

Sublime Text & SublimeLinter

https://github.com/SublimeLinter/SublimeLinter

Loop performance

Don't Code This


for(var i in arr) {
	console.log(arr[i]);
}
						

Code That


for(var i = 0, len = arr.length; i < len; i++) {
	console.log(arr[i]);
}
						

Loop performance

JSPerf results (Chrome 27):
For..in loop:    4,076 ops/sec
Cached For loop: 326,242 ops/sec

80x FASTER

I usually don't have to loop through a million things at a time!

(Besides, that for in loop is much easier to read!)

OK, Some things to keep in mind...

  • Don't forget to consider code readability & maintainability!
  • In the real world you have to get stuff out the door. Analyze to determine where your performance is the weakest and focus there.
  • That said, remember that every improvement adds up.

Add this to your toolkit:

Chrome Profiler

Discover Dev Tools - Chapter 6 (Code School)

Pitfalls

The Javascript Konami code


"use strict";
					
  • Prevents accidental globals
  • Safer eval()
  • Disables with (too confusing)
  • Prevents duplicate function/object arguments
  • And more!
  • Best of all, it's just a string!

I'm ignoring you

(IE10 understands it though)

WTF, parseInt?

Don't Code This


var nine = parseInt('09'); // Could be zero!!!
						

Code That


var nine = parseInt('09', 10);
						
...Exactly which radix is chosen is implementation-dependent. ECMAScript 5 specifies that 10 (decimal) is used, but not all browsers support this yet. For this reason always specify a radix when using parseInt.

No global variables!

Don't Code This


function swap(array, a, b) {
	temp = array[b];
	array[b] = array[a];
	array[a] = temp;
}
						

Code That


function swap(array, a, b) {
	var temp = array[b];
	array[b] = array[a];
	array[a] = temp;
}
						

Be careful chaining var

This is fine


var a, b;
						

Be careful chaining var

But Don't Code This


var a = b = 2;
console.log(window.a); //undefined
console.log(window.b); //2, oh no!
						

Code That


var a, b;
a = b = 2;
console.log(window.a); //undefined
console.log(window.b); //undefined
						
Pssst! Hey, by the way... those last three issues are all fixed by strict mode. Just sayin'

No hoisting!

Don't Code This


greeting = 'hello'; //evil global variable
function f() {
	console.log(greeting);
	var greeting = 'goodbye';
	console.log(greeting);
}
						

Output:


> undefined
> goodbye
						

No hoisting!

Behind the scenes this becomes


greeting = 'hello'; //evil global variable
function f() {
	var greeting;
	console.log(greeting); //undefined (NOT 'hello'!)
	greeting = 'goodbye';
	console.log(greeting); //sup yo
}
						

Solution: Define your variables in the top of your file/function to avoid surprises!

Semicolon insertion

Don't Code This


return
{
	hotDogs: 'tasty'
};
						

Code That


return {
	hotDogs: 'tasty'
};
						

Be specific about undefined

Don't Code This


if(n == undefined) { /*...*/ }
						

Code That


if(typeof n === "undefined") { /*...*/ }
						

Be specific about undefined

Here's why


var n;

// OK - prints true:
console.log(n == undefined);

// OK - prints true:
console.log(typeof aNonExistantVariable == 'undefined');

// BAD - this throws an errror:
console.log(aNonExistantVariable == undefined);
						

Well, you shouldn't have a non-existant variable in the first place!

Be specific about undefined

OK, Here's also why


function bad() {
	var undefined = "Problem?"; // Still works in strict mode!
	// ...
	if(n == undefined) {
		// This code will only run if n equals "Problem?",
		// and it probably doesn't.
	}
}
						

Protip: Don't be that guy that makes an undefined variable.

Stick with ===

Don't code this


var n = '';
// ...
if(n == 0) {
	// This code will be ran because '' == 0 is true
}
						

Code that


var n = '';
// ...
if(n === 0) {
	// This code won't run because '' === 0 is NOT true
}
						

Truthy Madness

Expression Result
'' == "0" false
'' == 0 true
0 == "0" true
false == "false" false
false == "0" true
false == undefined false
false == null false
null == undefined true
"\t" == 0 true
- Douglas Crockford (Javascript, The Good Parts)

Sources

Thanks!