Saturday, May 31, 2014

JavaScript Performance tip using a Closure

Here is a simple performance JavaScript tip using a JavaScript closure that is so quick to explain you have no reason not to keep reading.   Consider this: you want a function which will tell you the position on a rugby team for a certain number. Those of us who are familiar with the sport will know that in rugby, the various positions always have the same number.
  1. Loose head
  2. Hooker
  3. Tight head
  4. Lock
  5. Lock
  6. Flanker (blind side)
  7. Flanker (open side)
  8. No. 8
  9. Scrum half
  10. Out half
  11. Left wing
  12. Inside Centre
  13. Centre
  14. Right wing
  15. Full back
So for your first attempt you define a positions array in the global namespace and then a function to resolve the position for a given number.
var positions = ['No position', 'Loose head', 'Hooker', 'Tight head', 'Lock', 'Lock', 'Flanker', 'Flanker', 'No. 8',  'Scrum half', 'Out half', 'Left wing', 'Inside centre', 'Outside centre', 'Full back']

var getPosition = function(n) {
   return positions(n);
}
Everyone starts laughing at you at code review time. You get comments such as:
"Don't pollute the name space, re-write please."
"Did you even bother using JsLint?"
"Do you want fries with that?"

For your second attempt, you put the positions array into a function as a local variable.
var getPosition = function() {
    var positions = ['No position', 'Loose head', 'Hooker', 'Tight head', 'Lock', 'Lock', 'Flanker', 'No. 8', 'Flanker', 'Scrum half', 'Out half', 'Left wing', 'Inside centre', 'Outside centre', 'Right wing' 'Full back'];   // positions is a local variable
   return positions[n];
}
Back at the second code review:
"Well it's better, but you do realise that every time that function is called, the array is allocated?"
"But you said, don't pollute the global name space"
"Look we have standards here, don't pollute global name space and don't incur performance costs when you don't need do"
"Ok"

You leave the code review despondent and crestfallen. Back at your coffee stained desk, when your headphones are on low volume, you keep hearing the word closure, closure, closure from a few of the JavaScript nerds sitting near you.  That evening, you are having difficult getting to sleep.  Closure, closure, closure.  The word won't leave your head.  Closure, closure, closure.   Yeah you know that closures offer a way to encapsulate code in JavaScript, but this isn't about encapsulation. Wait a sec! Closures close over free variables and make them accessible to the lexical scope. Hmmm... This means you could do something like...
var getPosition = function () {
    var positions = ['No position', 'Loose head', 'Hooker', 'Tight head', 'Lock', 'Lock', 'Flanker', 'Flanker', 'No. 8', 'Scrum half', 'Out half', 'Left wing', 'Inside centre', 'Outside centre', 'Right wing', 'Full back'];   // positions is a local variable
    return function(n) {
        return positions[n];
    }
}()

console.log(getPosition(4));
What's going on here?
  • The inner function "closes over" the positions array
  • The outer function returns the inner function, which is then assigned it to the variable getPosition
  • The outer function is self invoking. This means the declaration, invocation and assignment will happen all at the same time.
  • Because it is the outer function which allocated the array and because the outer function is only invoked once, the array is only allocated once.
  • Because the inner function has access to what it "closes over" even after the outer function has executed, it means the inner function will have access to the positionsarray (that is only allocated once).
So you return to code review a little more sanguine. You get one comment:
"Third time lucky"

You might be thinking, it doesn't take that long to allocate an array in JavaScript is this not overkill? Well, it depends. Is your application needing to squeeze every nano second? Is the amount of data you need to initialise a lot more than 15 elements in an array? These are pertinent questions of course. But the technique is a handy one to know because encapsulation is clearly not the only advantage of closures.

No comments:

Post a Comment