Writing efficient JavaScript

This entry shows simple techniques to fulfill the JavaScript compiler optimization process which results in faster running code. Especially in games you immediately notice frame drops and when the garbage collector has to hit in with a big stack of work to do.

Monomorphism:

When declaring a function with 2 parameters the compiler takes you by word and gets rough if the parameter types, parameter count or return type of the function changes. Programs in general tend to work better with expected monomorphic data structures, the same counts for compilers.

Unfolding:

The compiler can resolve a variable’s value at compile time and unfold it (in best case), so try to express as much as possible before the program actually executes. Constants as well as variables can be unfold as long as they don’t make use of any runtime related computation.

Inlining:

The JIT compiler can figure out, which part of your code gets commonly executed. By splitting your functions into small chunks it can inline them at compile time and trace hot functions later easier to allow even faster execution.

Declarations:

Avoid declaring functions/closures and objects inside frequently called tasks. Objects (functions are objects too) get pushed into the heap which is affected by the garbage collector, where a lot of wat & wut is required to determine the next step (like freeing or not).

In contrary declaring variables performs very fast because they get pushed into the stack. E.g. a function has its own stack frame where all relative variables get pushed into - whenever it exits it’s stack gets immediately freed up.

Arguments:

Function calls are expensive (if the compiler cannot inline them). Try to use as less as possible arguments to make a call and don’t modify arguments inside a function.

Data types:

Try to make as much use as possible of Numbers and Booleans, they are a lot faster in comparison to other primitives. E.g. declaring a String turns into a big chunk of garbage because Strings are complex objects with many pre-shipped properties, behind the scenes.

Also avoid working with negative numbers and doubles with many decimal places.

Strict and abstract operators:

Attempt to use triple equality operators like “===” (strict) over “==” (loosely, abstract). Going strict guarantees the compiler to expect an specific value, so there is no need to compare the expression with multiple cases (eg. n>0=^true), which ends up in better performance scenarios at all.

Toxicity:

The following is a list of language features, which reduce or block the code optimization process.

  • eval
  • with
  • try/catch

Objects:

Object instances usually try to share the same hidden classes, be careful when adding a new member variable to an instantiated object since a new hidden class will be created and things are getting more complicated for the compiler (for you probably as well).

Loops:

Cache your array lengths and use arrays with monomorphic types. Avoid usage of “for..in” and looping over objects in general because it’s especially slow.

The continue and break statement act faster than the if statement’s body inside loops. Hold your loops clean and outsource everything into small sub functions, so the compiler feels more comfortable. Also using the prefix increment operator (++i instead of i++) gives small performance power-ups.