Writing efficient Javascript : A few tips
The speed of an application does matter, whatever that application does. On the Web, you’ll find quite some post or answers that suggest you shouldn’t care anyhow about speed in the early stage : just wait for the application to work, then benchmark/profile it if it is slow. The argument being that a -possibly huge- amount of time could be lost in optimizing a part of the code that will not prove critical or, even worse, get discarded.
I quite agree, yet i think there’s even a better advice to give : only write fast code, and your application will be fast.
My point here is that there are a whole set of good habits specific to javascript that you can get when writing Javascript, that do NOT take longer to write, and that will not also make your code run faster… but also make it easier to read, debug, maintain.
Best example of such habit is to cache a repeated computation into a var : it will run faster, require less typing / less reading, and when hovering your mouse over the var in your debugger, you can check the cached value at once when debugging…
I’ll try here to explain such a few habits i’ve taken over time to write fast code right from the start. Admittedly, before it becomes an habit, it might take you more time to code that way than just like you’re used to. But hopefully that cost will drop and since most of the time you’ll end time typing less, you’ll code faster… faster code.
Obviously, even with those good habits, you’ll encounter issues where your whole algorithm has to be changed to speed things up. I won’t cover that ‘big picture’ here. But was is specific about Javascript is that it is both a interpreted AND a compiled language, and wether the JIT (Just In Time compiler) triggered or not, Javascript has a high overhead, so one has to deal with great care with the ‘details’ : i’ve seen more than once a 2X or 4X boost just by applying a super-simple rule. On the other hand, compiled languages’s compilers are so smart than it is hard to outsmart them with simple rules.
Hopefully with some practice most of those rules will become just the way you write code, for instance, i did quite ‘forgot’, with time, that Javascript was not a typed language : now i’m sometime surprised to read some code which uses a single var to hold differently typed values, my first thought being that it won’t work… then i remember Javascript is not typed : it will work… just slower.
Here are the few guidelines i ended with.
In fact i have more advices, so more to come in case you show some interest in all this !
• Make types obvious.
• Types Again : Choose the right one
• Do not create garbage.
• Cache, cache, cache !
• Misc tips
A) Care about Types : make Types obvious.
Wether your code will be interpreted or compiled, you have to deal with types to write efficient Javascript. When interpreted, using the ‘smallest’ type and not changing it will simplify the engine’s work (which can ‘flag’ a property as being an integer, for instance). When compiled, things gets more complicated : to produce machine code, the compiler has to bet on the types of the variables/array/Object properties/return values before compiling (using data from the first calls made).
So the conclusion is quite simple : since you can’t declare the types, you have to make them most obvious to guess for the Javascript engine.
Below i give some advices i’ve seen to prove very efficient, especially on Chrome and its V8 engine, but not only.
A1) Make Types Obvious – functions :
Avoid function taking differently typed parameters or returning differently typed ones.
In every function you write, every parameter should have one and only one type, and return type should always be the same. ( use consistent arguments and return types ).
So try to avoid :
// compute a screen area with some numbers (float) var someArea = computeArea(30, 40); // compute a screen area with some figures relative to the screen size var anotherArea = computeArea("10%", "25%"); function computeArea ( width_Integer_Or_String, height_Integer_Or_String) { width_Int_Or_String = parseFloat ( width_Int_Or_String ); height_Int_Or_String = parseFloat ( height_Int_Or_String ); ... }
Rather build two functions :
// compute a screen area with some ints var someArea = computeArea(30, 40); // compute a screen area with some figures relative to the screen size var anotherArea = computeRelativeArea(10, 25); // computes the area covered by the two (float) arguments. // float_width/float_height is a float describing the area width/height in pixel. // returns the area (float) function computeArea ( float_width, float_height) { ... } // computes the area covered by the two (float) arguments. // float_width/float_height is a float describing the relative area width/height in percent vs screen width/height // expl : 50.0 stands for half width. // returns the area (float) function computeRelativeArea( float_relative_width, float_relative_height) { return computeArea( float_relative_width * screenWidth / 100, float_relative_height * screenHeight / 100); } // Rq ; This way to write those functions avoid the use of strings, and that // computeRelativeArea will be a piece of cake to compile after computeArea is compiled.
You might not have the choice for your input arguments : in this case do write a ‘hub’ function that will redirect to other functions, each being strictly typed (and hence optimized by the engine).
Notice that a few engines (i’m sure for V8 and Chakra), do understand type checking, so for instance in this code :
if (typeof someValue == 'number') { // here the engine knows someValue is a number. ... } else if (typeof someValue == 'string') { // here the engine knows someValue is a string. ... } }
A2 ) Make Types Obvious – var :
1) Never use the same var to hold differently typed values. It will not ‘save’ a variable, it will only confuse the engine. And anyway, it can only make your code clearer.
So no… :
var foundIndex = 12; ... compute with a as an int ... a = 'answer is ' + a; // NOPE !!! console.log(a);
But rather … :
var a = 12; ... compute with a as an int ... var answer = 'answer is ' + a; // YES !!! console.log(answer);
The speed cost of switching type might be dramatic : i once saw some code which was using a var to store an item index (integer), or ‘null’ (not an integer) when the item was not found.
Just switching to the classic convention of ‘-1 means not found’, and hence using only integers, did speed up the algorithm by 4 !!!
2) Give a (possibly default) value having the right type as soon as you declare them.
This not only make the types obvious for the engine… but also for you.
So no more :
var anInt, aFloat, myObject; ... compute things anInt = some int; ... compute things aFloat = some float ; myObject = some object;
But rather :
var anInt=0, aFloat=0.0, myObject = null; // now types are obvious.
Notice that even if the code never uses the default value, smart compilers won’t execute the first assignment, and will just understand it as a type hint.
A3) Make Types Obvious – class instance data properties
In the same way as with vars, you shouldn’t change the type of any object data property. Here again, this can only improve clarity for the reader or you.
And, just like for your vars, initialize the properties as you create them with, a default value of the right type.
But there are two more rules : Do not add properties on the fly on any object : You should have the habit, when adding a property at some point in your code, to add it also in the constructor.
In the same manner, never delete a property, rather set it to a falsy value (null/0), or if you really need this notify the value is not to be used, use a boolean to store the property status ( this.isWidthValid = false; ).
Remember that, if you need flexibility on the input (expl : for an object’s size an int would mean pixels, when a string like ‘30%’ would be relative to the screen size), you can still use getters to process the input on-the-fly and always store the value with the same type (in the example, as an integer).
// example of a width getter / setter Object.defineProperty( MyClass.prototype, 'width', { enumerable : true, get : function() { return this._width; } , set : function (val () { if (typeof val == 'string') { this._width = parseFloat(val)*screenWidth; } else if (typeof val == 'number' ) { this._width = val; } } } ); // Notice that width now uses a _width property // let's define it on the prototype as hidden to have it hidden on all instances : Object.defineProperty( MyClass.prototype, '_width', { enumerable : false, value : 0 }); // don't forget to initialize _width in the constructor by setting this._width=0; !!!
A4) Make Types Obvious – leave your classes alone !
Since the JS Engine might attempt to build a C++ class behind the scene to compile parts of the code, it is very important, besides using ‘typed’ data properties, to keep the whole class methods unchanged once you’ve defined
it.
Do not change methods of your class on-the-fly : after all, by deciding of the right function parameters and class properties, you shouldn’t need to change any method anyway. There are always some way to keep the flexibility you need while keeping your class ‘constant’.
In other words : what about pretending, when coding, that Javascript is a compiled language ?
The constructor and the prototype are a fixed class definition just like you can have in, say, C++.
No last-minute change.
Notice that you can have the engine check for you if you do change an instance by using Object.seal in the constructor / on the prototype.
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal)
A5) Advanced tip : Avoid using null.
This one is tougher, and applies only to special cases : When you are using null, you are only giving a small hint to the engine : it will be dealing with an Object (or a pointer, if you like).
So what about helping it for real and create a default instance of the class that you’ll use only for initialization/’declaration’ purposes ?
function Rectangle ( x, y, w, h ) { } Rectangle.default = new Rectangle( 0,0,0,0 );
later used with :
var rect = Rectangle.default; for (var i=0; i < rectangleArray.length; i++) { rect = rectangleArray[i]; // ... do something with rect }
In fact, there’s a coding pattern that you might want to use where you don’t use null at all (your class is a non-nullable type) and make use such a particular instance, but the discussion about it is out of topic i fear.
(interesting post here : http://twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing-the-billion-dollar-mistake)
In fact quite some engine would understand, in the example above, that rect is a Rectangle, but in fact i once saw a case where the engine could not guess the type.
It was somehow like :
function computeSomething() { var someInstance = null; var instanceIsValid = false; if (Math.random() > 0.5) { // head or tail ? instanceIsValid = true; someInstance = new someClass(); } // ... // ... later ... if (instanceIsValid) { someInstance.someMethod(...); // But what is the type of someInstance ? } }
Using a default instance solved this issue, allowing a full optimization of the function. (which became way faster of course).
B) Types Again : Choose the right one
B1) Choose a cheap type for your vars / properties
int32 > double (IEE 754) > string > Map > (sealed) Class instance > dynamic object
To store the informations required for your application, always use the cheapest type possible.
In Javascript, int is incredibly cheaper than other types : Chrome’s V8 will ‘box’ 32 bits integer, and can use them with a very small overhead.
As soon as you are using double (64bits), you might have to load it, and other types have even higher overhead : go for the int !
String should be used only for user output, and quite nothing else : manipulating string is a highly inefficient manner of dealing with data and they create garbage.
So do NOT write
if (this.direction == 'up') { // ... move up }
but rather :
// define this somewhere .... var upDirection = 0, downDirection=1, ... ; // ... or as a class static property : Character.prototype.upDirection = 0; // ... or ... : Character.prototype.directions = { up : 0, right:1, ... }; // then later... if (this.direction == upDirection) // or ... if (this.direction == this.upDirection)
A story about strings : to see how much using strings could cost, i once optimized a function that used ‘up’, ‘down’, ‘right’, ‘space’ and a few other strings to change a sprite direction or behavior in a game.
Result was that, by using integers instead of strings, 350kb of garbage per second were saved on Chrome.
Worth the deal i would say.
Rq that to use integers and still keep a clean code, you can use an ‘enum’ built with an object literal :
// in a var or in a 'static' prototype property var petType = { none : 0, dog : 1, cat : 2, wombat : 3, unicorn : 4 };
Rq also that not using strings will allow better minification of your code, hence reduce the page loading time.
B2) Collections : Use a cheap Collection type
Typed Array > Array > Map > Object > Whatever data structure ( tree… )
Just like with single values, you can win a great deal of speed by choosing, from the start, a cheap data structure. The cheapest is an array. when you’ve chosen the structure, have it hold the cheapest type that you can.
Tips for Arrays :
pre-allocate arrays if you know they’re gonna be big.
var myArray = new Array(100000);
Whenever it makes sense, create an array by using slice() on an existing array, then replacing values : this way you allocate only once and the engine is aware of the type.
Do not use mixed type arrays. If you somehow need to, either create a container class, or use several arrays in parallel.
Rq that obviously you should avoid sparse arrays. Use null if you need to, but do not keep undefined values : they will only raise your chances of a slower processing.
(so if you create your array with new Array(100); just do a for loop to fill it right after. Same goes if you enlarge your array by increasing its length.)
Trees (bsp trees, quad-trees, …), Heaps, …, while very nice on the paper, behaves poorly when implemented in Javascript : not only each step through the tree take a pointer indirection, but also a type check. One has to be sure, especially when dealing with small collections, that this overhead will not kill the savings that could shown with a big collection. Yet in some cases they prove very useful… Beware of the benchmarks that shows how fast is some super solution is with 100.000 elements when you’re gonna use it with 200 elements…
B3) Avoid using boolean properties.
When using a boolean property within a class, the engine has only two bad choices : either use a byte to store it, and un-align all data after-wise, or use 32 bits (or 64), and waste memory space.
So ask yourself if you can’t choose another way around.
If you are using a boolean to flag, say, an object as ‘dirty’, meaning it will later have to be processed, not only you are using a boolean, but you are doubling the work to be done, since later you’ll have to iterate through objects to see which one is dirty : a better solution is to directly push this object into a dirtyObjects array that you’ll later process.
Most often, a boolean is a weak information that you can easily improve : compare for instance a isThereSuchAnObject method (that returns a boolean) with either indexOfSuchObject (that returns index or -1) or getMeFirstSuchObject (that returns an object or null). No wonder that either two last methods will prove more useful in the long run : at design time consider that a function only returning a bool as suspect.
Advanced tips, for the one fluent with binary operators : If you are using several flags, pack them all within a single integer, and use a mask and AND (&) or OR (|) operators to read/write the relevant flag.
Small example :
// (halloween) MASKS var IS_WEIRD = 1 << 0; var IS_TREAT = 1 << 1; var IS_TRICK = 1 << 2; var IS_UNDEAD = 1 << 3; var IS_GHOST = 1 << 4; // use of masks; var someObject = ... ; // test if the object is weird var isObjectWeird = someObject.flags & IS_WEIRD; // now make the object undead someObject.flags = someObject.flags | IS_UNDEAD; // now make the object not weird someObject.flags = someObject.flags & (!IS_WEIRD);
B4 ) Use the wonderful types HTML5/ES6 offers.
Well this one depends on your target platform. But you target Desktop, meaning Chrome or Firefox, this is a no-brainer : you should use the wonderful new types of html5 :
Typed Arrays, Map, Set, WeakMap, WeakSet, Blob, Symbol, Proxy : be creative !
a Map will be faster when used as a Hashtable than an object {}. And you can use an object as key, which allows to easily code powerful features.
a Set can be a wonderful class to help you count objects, or way faster than indexOf if you only want to know if some item is there (… and faster than any implementation of a Set you could write yourself…).
WeakMap and WeakSet allows you not to care about some clean-up operations you might otherwise have to do when you stop using some object. So faster again. And cleaner code. You can also easily create ancillary data with neither a risk of memory leak nor the cost of breaking an existing class by changing it live.
Blob isn’t that new, but is widely supported now, so do not use toDataUrl any more, but rather toBlob, way faster. And you can use your blobs in web workers to compute things in the background without slowing your application !!
If you wonder about the support of a feature, have a look here :
http://caniuse.com/
or here :
http://kangax.github.io/compat-table/es6/
C) Do not create garbage
Writing fast code also requires you to avoid creating garbage. Javascript has that convenient way of disposing of the unused objects for you, but that comes with a huge cost : from time to time, the engine has to go to a full stop that can last up to a few milliseconds, which might very well result in a frame miss or more generally a bad user experience. Even a super-fast code can be killed by the evil garbage collector having to dispose too many objects.
Another reason not to create garbage is that creating object has an important cost : the memory allocation.
Keep also in mind that successive allocation/disposal of objects will fragment the memory, leading to a mandatory garbage collection that can require way more memory moves than just the objects size would let you believe.
As a side comment, notice all garbage collectors do not behave the same : Chrome is the best, that can do a light pass or a full pass depending on an estimation of the time left (!sweet!), when Firefox does its g.c. often, … and often creates a frame miss : that’s why so many video games offers a poor experience on Firefox.
Whatever the browser, the lower the garbage, the better, and you can target 0 object creation in most of your frames with little efforts. However, you can’t target 0 garbage creation since function calls (amongst other mandatory operations) will create ‘system’ garbage that will have to be recollected later.
C1) Do not create garbage – Re-use your objects
You might need some temporary object ( [], {}, Map, some class instance, …) to compute something, that you’ll throw away afterwise. In this case, most likely you don’t need to create such a new object on each function call : store it once and re-use it (maybe clearing some values each time), so you avoid to create garbage and summon the evil garbage collector.
An array is cleared with someArray.length = 0, for instance.
For hash-maps ({}), use a default falsy value.
For instance methods, you might want to add a reset() method. Remember, however, that the constructor function is… a function, that you might call to reset an object :
function Point(x,y) { this.x = x; this.y = y; } var somePoint = new Point(12, 45); // Now i can use the cttor again to change the values : Point.call(somePoint, 42, 42);
A few remarks about re-use :
• Pooling is a way to handle re-use nicely. I wrote an article about it that might interest you :
https://wordpress.com/post/gamealchemist.wordpress.com/36
• The benefit might not show easily in benchmarks since you’ll trade the cost of the reset against a less probable G.C. Since a G.C. occurs quite randomly, and during a G.C. the engine is paused, you just can’t measure any very relevant time…
• … Still you can use, in the developer tools, the graph showing the memory use. G.C.s can be noticed by a vertical drop in memory use. You might be surprised how much a small ‘hunt’ for object creation in your code can cool down the G.C. rate.
• Readability is worsen by this trick : As a naming convention, i do use __ as a prefix for the name of those optimisation variables. Yet you have to store them on the class, and reload them into a var before use. Somehow verbose and puzzling.
• There is a trade-off time vs memory strain. The cost of reset, if too expensive, might overweight the gain in G.C..
• Because of all this, re-use objects only if it’s easy : put a comment to flag that an optimization could be done here otherwise, to avoid starting an early (evilish!) optimization.
C2) Do not create garbage – Do not write or call functions with too much parameters.
Yes, arity (==argument count) does affect memory !
When calling a function, especially in strict mode, some work has to be done and some memory/heap used : keep the number of arguments low (<4) or you’ll summon the evil garbage collector too often.
Again here, with speed boost and memory savings comes clarity / ease of maintenance / debugging / …
Let’s see an example : the real example of the 9 arguments drawImage function of the canvas :
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
Wow !! unreadable. Imagine now that Rectangle was a default type in JS (…). We could have the following function signature :
context.drawImage(img, srcRect, dstRect);
Better, no ???
(Anyone preferring the 9 arguments version should call his/her doctor right now. 🙂 )
So here the idea is that if a function or method has too many arguments, maybe you missed something (do you need such flexibility ?), or maybe it’s time to create a container class (Rectangle in the above case), that most likely will prove useful to clean up your code.
C3) goto D3;
D) Cache, cache, cache !!!
D1) Cache your expressions
I’m always surprised to see, in Stack Overflow questions for instance, code such as this one :
for (var i = 0; i < someObject.anArray.length ; i++) { if (someObject.anArray[i].point.x > someObject.anArray.point.y) { someFunction( someObject.anArray[i].point ); } }
It *should* hurt one’s eye to see such redundancy. Every time in the loop you’ll have several pointer indirection , and the JS Engine might very well not be able to see that the objects/properties are constant. So much time loss.
Here again, coding with performance in mind matches with clearer/neater/… way of coding. Rule is to cache everything you’re going to use again into a local var. **Everything**.
Let’s see the cached version :
var pointArray = someObject.anArray, thisPoint=null; for (var i = 0; i < pointArray.length ; i++) { thisPoint = anArray[i]; if ( thisPoint.x > thisPoint.y ) { someFunction( thisPoint) ; } }
!!!
So every time you write an indirection (something.someProp) for the second time, create a var and re-use it.
D2) Get things out of the loop
It’s quite the same idea as caching : any time you see the same expression computed/loaded again and again in a loop, just compute it/load it in a var once before the loop.
A small example might be a conversion from degrees to radian of an array :
var degToRad = Math.PI/180; // computed once for (var i=0; i<angleArray.length; i++) angleArray[i]*=degToRad;
D3) Cache your function calls
Something quite specific to Javascript is the closures that you can create easily with it. One more efficient way of creating such a closure is to use Function.bind to create a new function that has a given ‘this’, and possibly some arguments already set. If you are to use a function with the same this/and/or arguments again and again, you *might* want to bind a function to the fixed arguments to get things done faster : not only you create less garbage since you’ll later call with less arguments, but also the type checking will only happen once (when binding), saving even further time on each call.
so imagine you want to draw some tiles on the screen. The ‘naive’ way would go :
for (loop on X) { for ( loop on Y) { var tile = tile at X, Y; context2D.drawImage( tilesetImage, tile.x, tile.y, tile.w, tile.h, X, Y ); } }
now each tile will have the same location (x,y,w,h) on the tile image, the tile image won’t
change, and the context2D won’t change either : you can create a drawer function for each
tile with
// in the constructor of the Tile object this.drawAt = context2D.drawImage.bind(context2D, someTile.x, someTile.y, someTile.w, someTile.h);
You can use later with :
for (loop on X) { for ( loop on Y) { var tile = tile at X, Y; tile.drawAt(X,Y); } }
Notice, once again, that readability improved along the way.
Yet bind comes with a cost : it is a new object creation, which implies overhead, allocation, and maybe garbage collection. So use it only if the benefit is obvious and the writing is easy, otherwise keep that advice for ‘late’ optimizations (the ones that you do after seeing an issue / benchmarking ).
E) Misc
E1 ) Order your conditionals
Here we’re talking about a small effort providing a small benefit.
When you have a conditional, take just one second to think about the most probable case, and put it first. This way you won’t have any branching, saving a few CPU cycles.
function giveMe5() { if (Math.random() < 0.95) { return 5; // return 5 most of the time, give 5 with no branching } else { return 0; // sometimes you don't want to give 5. } }
E2 ) Exit soon and explicitly
There are quite a few functions you’ll write that have obvious cases, handle first the easy cases with a clear return statement instead of writing a few if/else that will make the code harder to understand.
Notice that this rule might collides with the ‘order your conditionals’ rule, you’ll have to think of the benefits of returning early vs not branching. Benefits are little, in doubt prefer a nicer code.
E3 ) Class properties and methods : Order your properties and methods, keep their count low.
This one is also an easy save, order the properties of your class by ascending frequency of use : the first properties are faster to access. And use a low count of properties/methods : the lookup time will go down on every use.
There’s also a benefit for code clarity : the most used are most likely also the most important.
And if a Class is starting to have a lot of properties, it’s anyway probably the time to use composition other inheritance, or to split things up.
Think about a DOM object for instance, imagine the mess that would result from having all the properties that are exposed through the `style` property directly defined on the class itself !
Another idea is that if you need some rarely used properties, do not hesitate to store them all in a single object – the DOM style is again a good example : unless there’s a reflow and a need to re-compute the DOM object position, the style won’t be used. Benefit in both clarity and look-up access time.
E4) Use strict mode.
Strict mode allows the engine to live with a far less messy version of Javascript, that
allows quite some optimizations to be performed easier. I won’t argue much here : just “use strict”; 😉
E5) Warm-up your functions.
If (and only if) you are sure some function will be called numerous times and will ‘stand in the way’, you can trigger the JIT by calling it 50 times before really launching the application. This way you won’t have that little slow down that shows when the engine freezes to optimize some code during the first frames. Yes, i am thinking about html5 games here.