Feature Detection and Function Efficiency within JavaScript

By  on  

Efficiency in code execution is incredibly important, especially when the given function is used repeatedly.  You often see repeated function calls within JavaScript frameworks.  When you work on said frameworks, you need to ensure you've hit ever micro-optimization possible.  One micro-optimization you can make is running conditionals before you create a function, instead of each time the function runs.  Let me illustrate a basic example.

The Bad

The following would be considered inefficient:

function something() {
    if('something' in obj) {
        // something
    }
    else {
        // fallback
    }
}

The code above is inefficient because the conditional is run upon each call of the function.  Let's do better!

The Good

Instead of running the conditional check within every function call, run the conditional before setting the function:

var something = ('something' in obj) ? function() {
    // something
} : function() {
    // fallback
};

This pattern is especially applicable when using feature detection -- i.e. the value of the conditional never changing.  Of course the conditional evaluation is fast but why calculate easy conditionals more than once? You shouldn't, of course.  Keep this pattern in mind when creating your own frameworks -- don't repeat code!

Recent Features

  • By
    How to Create a Twitter Card

    One of my favorite social APIs was the Open Graph API adopted by Facebook.  Adding just a few META tags to each page allowed links to my article to be styled and presented the way I wanted them to, giving me a bit of control...

  • By
    LightFace:  Facebook Lightbox for MooTools

    One of the web components I've always loved has been Facebook's modal dialog.  This "lightbox" isn't like others:  no dark overlay, no obnoxious animating to size, and it doesn't try to do "too much."  With Facebook's dialog in mind, I've created LightFace:  a Facebook lightbox...

Incredible Demos

  • By
    Firefox Marketplace Animated Buttons

    The Firefox Marketplace is an incredibly attractive, easy to use hub that promises to make finding and promoting awesome HTML5-powered web applications easy and convenient. While I don't work directly on the Marketplace, I am privy to the codebase (and so...

  • By
    Create Keyboard Shortcuts with Mousetrap

    Some of the finest parts of web apps are hidden in the little things.  These "small details" can often add up to big, big gains.  One of those small gains can be found in keyboard shortcuts.  Awesome web apps like Gmail and GitHub use loads of...

Discussion

  1. Manny Fleurmond

    Mind blown. Keep forgetting functions can be used as objects and can be assigned like that.

  2. Thomas

    I don’t find this applicable in a fair number of situations.
    A fairly common example: what if I call this function in several places in my code? I mostly find it better to check for support in the function itself.
    Also, I often like to think that it is more the functions job to check for support.

    • ConcernedCitizen

      Calling your function in several places is the exact reason David’s solution is an improvement.

      If you call function “something” three times in your code, your method would try to detect the feature each time.

      David’s solution only checks the feature once, and the function is defined based on the result of the detection. So if you call “something” three, four, or twenty times in your code, you’ve only needed to check for the feature the one time.

  3. I would consider using a conditional instead of the ternary operator, specially if the functions aren’t too short:

    var something;
    if('something' in obj){
      something = function(){
        // something
      }; 
    } else {
      something = function(){
        // fallback
      }; 
    }
    
  4. Brendon

    Awesome, consider it adopted :)

  5. I’m getting mixed results (I may be doing this wrong).

    http://jsperf.com/nrd-feature-detection

  6. Christophe

    @Martin: I think the tests should be that. You define function only once, and then you call them multiples time. In the first test, you test in the function everytime the function is called, in the second test you test only once when the function is defined.

    However, it doesn’t give any benefit regarding the jsperf:
    http://jsperf.com/nrd-feature-detection/2

  7. Robert Smith

    I personally prefer the use of the ternary, when used as an assignment like in this particular pattern I think it’s a little easier to read than the IF block.

  8. Adam Bankin

    I’ve used the following to do this

    var myFunction = (function () {
      var detectedFeature // do your feature detection here
    
      return function () {
        if (detectedFeature) {
          doStuff();
        } else {
          doAlternateStuff()
        }
      };
    }());
    
    • Instead of returning a function with conditionals inside, return a function based on conditionals.

      var myFunction = (function(){
      	var detectedFeature; // do your feature detection here
      	if(detectedFeature){
      		return function(){ //feature detected, return a function and end the function
      			doStuff();
      		}
      	}
      	return function(){ //feature not detected, return a fallback function
      		doAlternateStuff()
      	}
      })();
      

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!