Introduction
Hey there, so this is the first article about things I've been putting to good use code-wise. Like a lot of developers I learn by doing, but I also learn from other, more experienced developers where I can. Over the past few months I've been spending more time than ever with the Canvas tag, WebGL and JavaScript in general and I thought it would be fun to compile some of the things I've learned recently as well as a few tricks I've known for some time. Some of them are very specific, some of them are broad and they range in how complex they are so hopefully everyone will find something they like!
1. Prototype it
Let's start with an easy one. So you have a great idea for an experiment. Do a quick prototype of the most complex part of it to see whether the tech can stand up to it. WebGL, for example, is really powerful since it hooks straight into the GPU, but don't forget it's being accessed from the JavaScript engine which will be much slower than your graphics card. Your great idea might be undermined by something as simple as that
2. Use three.js for 3D
Like my good friend Hakim, I'm all for understanding the underlying technology that you're using. I think it's important to know how the layer underneath what you're doing is going about things. With that said, however, for 3D, three.js takes away so many headaches for you so use it! It can be used with a Canvas renderer, a WebGL renderer and an SVG renderer so you should be able to find something that suits your requirements.
3. Avoid setInterval
This is a really important point for anyone doing any animation in their JavaScript. Why is it a problem? If you're calling something every 20ms with setInterval, but what you're calling takes longer the browser doesn't care, it's going to start the next call before your first one is complete. Instead you should use, at least, setTimeout to call your function. At the end of it you set the timeout for the next call and so on.
In reality there's a new-but-half-implemented function called requestAnimationFrame which is just brilliant. It acts pretty much like the setTimeout save for the fact that it doesn't run for tabs out of focus (saving battery life, for example, on mobile devices) and it is native to the browser so it can schedule it when it's best. For more info and a super useful snippet check out Paul Irish's blog.
4. Go backwards
This is a pretty basic optimization you can make to your loops if
you're not doing so already. Go backwards, and use while loops.
So this:
for(var a = 0; a < arr.length; a++) {
is slower than
// do something
}
// assumes arr exists ;)
Now admittedly you might not save much, it really depends
what you're doing inside of those loops, but if you're
trying to squeeze out the last bit of performance from
a Canvas / WebGL experiment it can be an easy win.
var aLength = arr.length;
while(aLength--) {
// do something
}
To be honest the main speed increase in the above is likely due to the caching of the array length. You could (and really should) actually take a look at JSPerf to really get an understanding of this and other JavaScript performance factors.
5. Use images
It's really tempting to draw things in Canvas particularly using the built in drawing methods. Where possible, however, you should really look to see if you can use images because it can drastically improve performance. For certain effects like shadows and blurs you may well have to do it in any case, but keep an eye for anything else you can do.
6. Cache me if you can
This is something I've been doing a lot of in my WebGL experiments. You really want to avoid getting references to variables, objects or, in fact, anything you can during your main loops. For that reason it's totally worth caching up your objects or vertices so you can access them really quickly when you're animating.
7. Stop selection
I love this little snippet for anything involving the
Canvas or WebGL:
// stop the user getting a
You might want to do that on your Canvas rather than
the document. I've just included the one I use for
my WebGL ones that take up most of the screen.
// text cursor
document.onselectstart = function() {
return false;
};
8. Avoid JavaScript based CSS
It's super easy to start stacking up CSS calls
in your JavaScript, especially if you use jQuery:
$("#someid").css({
The problem is that after a while your JavaScript
is awash with all these random chunks of CSS, but
you're also applying your CSS via the .css files
and potentially things can be difficult to debug.
It's much better, where you can, to use classes
and only use JavaScript to manipulate the values
you can't determine ahead of time.
position: 'relative',
height: '30px',
width: '300px',
backgroundColor: '#A020F0'
});
9. Callbacks in an object
I love this one, and I definitely didn't think
it up myself, but it's so neat and tidy. If you
have a load of callbacks going on you may be
used to doing them inline like this:
$("#someid").click(function() {
or alternatively just hooking a loose function
from your code like this:
// guts of the callback
/* returning false
* in a jQuery callback stops
* propagation and prevents
* the default behaviour
*/
return false;
});
$("#someid").click(mySuperFunction);
There are a couple of problems with these approaches.
With the first type it becomes difficult to unbind
the function later on if you need to. Sure you can
unbind all click handlers, for example, but you may
have a few attached and really you just want to drop
that one. With the second it's just a maintainability
issue - it's harder if that function is hidden away
amongst the rest of your code. Instead consider doing
this kind of thing:
function mySuperFunction(event) {
// more epic things happen here
return false;
}
$("#someid")
It's neat and tidy and it avoids both of the above issues.
.click(callbacks.mySuperFunction);
// all my callbacks are
// in this object
var callbacks = {
mySuperFunction:function(event) {
// more epic things happen here
return false;
}
}
// and later on...
$("#someid").unbind('click',
callbacks.mySuperFunction);
10. The long ternary if-statement
I totally learned this one from Paul Irish in his
11 More
Things I Learned From the jQuery Source video. And it's super handy
if, like me, you like the ternary if-statement. So I'm used to something like
this:
// depending on a's value
But what if you need to be, like, do this if the value is this,
and this if it's more, and this if it's even more. You know the kind
of thing? Yes, well in that case the long ternary is amazing:
// numberBasedOnA will be 200
// or 38. Lovely.
var numberBasedOnA =
a > 5 ? 200 : 38;
// now check this out...
var numberBasedOnA =
a < 5 ? 200 :
a < 7 ? 38 :
a < 11 ? 15 :
a < 15 ? 49 :
64;
// effectively 64 is like a default case
// when a >=15