Combining JavaScripts - Competing Onload Handlers

Scenario: You have two (or more) scripts. They work separately, but not when you combine them in one document. The most likely culprit is competing onload handlers.

JavaScripts will generally require some sort of initialization routine to be run once the document has all the necessary components in place, in particular, DOM elements required for the code. Sometimes it works to place the call to initialize the code at the end of the document, before the close body tag, but that is not consistently reliable for a variety of reasons. Calling the initialization routines onload is, or has been until recently, the method of choice.

Perhaps one initialization routine is called from the body tag onload attribute, while another is assigned to window.onload. One or another will not be called. If you have multiple assignments to window.onload each will overwrite the previous one as the code is parsed.

The purpose of this brief tutorial is to discuss various approaches to overcoming this problem, both old and new. The challenge to is to locate all of the onload function calls or assignments and to make sure that they are all successfully invoked.

Onload the Old-Fashioned Way

Depending upon when and by whom the code was written there are variety of places where one might find onload function calls or function assignments lurking. Although it is now considered poor practice to place event handlers in HTML attributes you may still find them there, in the body tag's onload attribute:

<body onload="doSomething(argument)">

It is quite simple to include multiple function calls onload in that location simply by separating them with a semicolon:

<body onload="doSomething(argument); doMeToo()">

One advantage of code using the body onload attribute is that you don't have to go looking throughout code to find window.onload assignments:

window.onload = doSomething;

Sometimes these statements are buried within the code and difficult to locate. Nonetheless, if you are using code that assigns a function to be called onload in this way you must find a way to reconcile that with other code also needing to be run onload.

One can place multiple function calls inside an anonymous function assigned to window.onload as follows:

window.onload = function() { 
  fn1Name(args);
  fn2Name();
}

Although the above practices still work perfectly well, they have fallen out of favor. The standard of unobtrusive JavaScript dictates that not only should JavaScript be removed from the document structure (i.e., not use HTML event handler attrubutes) but should also not obtrude on (have to commingle with) other code.

AddLoadEvent Functions

A better approach has been around and in broad use for quite some time: addLoadEvent functions, the original version most likely by Simon Willison.

function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}

The addLoadEvent function calls can be placed wherever you want. That is, there is no need to remove from the code in which they belong and combine in a single location:

addLoadEvent( functionToCall );

// example passing arguments:
addLoadEvent( function() { doMeOnload('Yo', 'baby!') } )

You can call as many initialization routines as you like with addLoadEvent and they will all be successfully added to the stack. However, use of addLoadEvent functions is not a magic bullet. Multiple window.onload function assignments placed ahead of the first call to addLoadEvent can't be collected, and window.onload function assignments placed after addLoadEvent function calls will overwrite its handling of window.onload up to that point. Also, function calls placed in the body tag onload attribute will render addLoadEvent ineffective.

The objective: if using addLoadEvent, window.onload or the body tag onload attribute, decide on one approach to initializing code onload and use it for all code in your documents.

The good news: if your code is written for browsers supporting addEventListener, or in the case of Internet Explorer, attachEvent you can use those methods to invoke function calls onload and leave the above problems behind.

addEventListener/attachEvent

The DOM Level 2 mechanism for attaching event handlers, addEventListener, and the roughly equivalent method used by Internet Explorer 5+, attachEvent, allow multiple event handlers of the same type to be attached to the same object without interfering with each other. Scott Andrew LePera is credited for the original cross-browser addEvent function:

function addEvent(obj, evType, fn, useCapture){
  if (obj.addEventListener){
    obj.addEventListener(evType, fn, useCapture);
    return true;
  } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
  }
}

The event file from dyn-web, dw_event.js, includes an add event function which can be used for onloads as follows:

dw_Event.add( window, 'load', init_dw_Scroll );
dw_Event.add( window, 'load', initRotator );

This approach appears to coexist amicably with window.onload and body onload.

DOM Ready

Sometimes one doesn't need the entire page including images to have completed loading before code can be initialized. This wait can be especially problematic if there are numerous and large images to be loaded. What is needed is some event that fires when the DOM is ready. Enter DOMContentLoaded.

Even though the DOMContentLoaded event is not supported by all browsers there have been numerous efforts to reconcile the cross browser differences and provide the same functionality. The large libraries and frameworks currently in vogue will generally have a function that you can use to initialize code once the DOM has loaded. For example, see JQuery's ready event.

If you are not using one of these libraries you can find code to serve the same purpose. See discussion and code at:

Back to top