Init-time branching

Probably virtually every web developer has done something like this at one point or another:

function myEvent(el, type, fn) {
  if (window.addEventListener) {
    el.addEventListener(type, fn, false);
  } else if (window.attachEvent) {
    el.attachEvent("on" + type, fn);
  }
}

This is absolutely normal, browsers are different, we have to take this fact into account and branch our code. One way to improve similar bits of code is by branching only once, when the function/method is defined as opposed to every time it's called. Like this:

if (window.addEventListener) {
  var myEvent = function (el, type, fn) {
    el.addEventListener(type, fn, false);
  }
} else if (window.attachEvent) {
  var myEvent = function (el, type, fn) {
    el.attachEvent("on" + type, fn);
  }
}

This way you get browser-dependent myEvent() function and there's no branching every time the function is called. While this may sound unnecessary, it could have an impact when a function is called many times in performance-critical situations, such as during drag-n-drop.

In a drag-drop case, it's likely that you need to get the current (computed) style of an element and also set it. Getting the computed style is different in browsers and is an ideal candidate for load-time branching. This is how it's done in the YUI DOM utility (source code), where this pattern was actually isolated from.

The DOM utility does more stuff, but the purpose of simply demonstrating the pattern you can say that it does something like:

// load-time branching
if (document.defaultView && document.defaultView.getComputedStyle) {
  var getStyle = function(el, property) {
    return document.defaultView.getComputedStyle(el, '')[property];
  }
} else if (document.documentElement.currentStyle) {
  var getStyle = function(el, property) {
    return el.currentStyle[property];
  }
}
 
// usage
var style = getStyle($('something'), 'fontWeight');

Another benefit of load-time branching is that you can branch only once and define multiple functions. For example if you've detected that the browser supports window.addEventListener it's very likely that it will support window.removeEventListener as well and not window.removeEvent. This should be approached carefully though, so that you keep in mind to branch based on object/feature detection and not on browser detection. For example don't be tempted to define getStyle() based on detection for window.addEventListener, although it will most likely work.

5 Responses to “Init-time branching”

  1. Pablo Cabrera Says:

    You could also use lazy definition to do your branching. Something like this…

    function myEvent(el, type, fn) {
      if (window.addEventListener) {
        myEvent = function(el, type, fn) {
          el.addEventListener(type, fn, false);
        };
      } else if (window.attachEvent) {
        myEvent = function(el, type, fn) {
          el.attachEvent("on" + type, fn);
        };
      }
    
      return myEvent(el, type, fn);
    }
    
  2. stoyan Says:

    Yes, thanks Pablo, you can definitely do this. I have it as a separate pattern worthy of an article itself 😉

  3. Marian Kostadinov Says:

    If somebody wants to use the standards compliant solution, the following “compat” code can also be used:

    (function() {

    var camelizeCSSProperty = function (property) {
    return property.replace (/\-([a-z])/g, function(string) { return string.charAt(1).toUpperCase() })
    }

    if (!(document.defaultView && document.defaultView.getComputedStyle)) {
    document.defaultView = {
    getComputedStyle : function (element, pseudoclass) {
    //pseudoclass not supported.
    return new function() {
    //Currently only getPropertyValue is suppored.
    this.getPropertyValue = function (property) {
    var result = element.currentStyle[camelizeCSSProperty (property)];
    return result;
    }
    }
    }
    }
    }
    })();

  4. extended options Says:

    Thanks for every other informative web site.
    Where else may I am getting that kind of information written in such a perfect
    way? I have a challenge that I’m just now operating
    on, and I have been at the look out for such information.

    My site; extended options

  5. purificadoras de agua Says:

    Very interesting details you have noted , thanks for posting .