3

I am writing an internal framework that can have no dependencies (i.e. jQuery, etc.) and am trying to implement my own DOM ready-style functionality. It seems that when a callback in the ready queue (array of callbacks to complete on DOM ready), if an exception is thrown inside that function, execution stops and continues onto the next callback (which is what I want), but Firefox will not report the error (log to the console, trigger onerror, anything). Am I doing something wrong?

I have implemented this using a combination of a pattern by Dean Edwards (http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/) and the jQuery source. I do not wish to implement just like jQuery because if one callback fails, the subsequent callbacks won't execute.

var readyCallbacks = [];

(function () {
    var currentHandler,
    fireReady,
    removeEvents,
    loopCallbacks = function () {
        for (var i = 0, len = readyCallbacks.length; i < len; i += 1) {
            currentHandler = readyCallbacks[i];
            fireReady();
        }
    };

    if (document.addEventListener) {
        document.addEventListener('readyEvents', function () { currentHandler(); }, false);

        fireReady = function () {
            var readyEvent = document.createEvent('UIEvents');
            readyEvent.initEvent('readyEvents', false, false);
            document.dispatchEvent(readyEvent);
        };

        removeEvents = function () {
            window.removeEventListener('load', loopCallbacks, false);
            loopCallbacks();
        };

        document.addEventListener('DOMContentLoaded', removeEvents, false);
        window.addEventListener('load', loopCallbacks, false);
    } else {
        // if < IE 9
        document.documentElement.readyEvents = 0;

        document.documentElement.attachEvent('onpropertychange', function (e) {
            if (e.propertyName === 'readyEvents')
                currentHandler();
        });

        fireReady = function () {
            document.documentElement.readyEvents += 1;
        };

        removeEvents = function () {
            window.detachEvent('onload', loopCallbacks);
            loopCallbacks();
        };

        document.attachEvent('onreadystatechange', removeEvents);
        window.attachEvent('onload', loopCallbacks);
    }
})();

Client.ready = function (callback) {
    readyCallbacks.push(callback);
};

Here is my test implementation. The console is written to and the DOM element has been manipulated. In IE error with the UNDEFINED_VARIABLE++; is shown in the console, but not in Firefox.

<!DOCTYPE html>
<html>
<head>
    <script src="Client.js"></script>
    <script>
        Client.ready(function () {
            console.log('logging before error');
            UNDEFINED_VARIABLE++; // This does not error in Firefox
            console.log('logging after error, not logged in Firefox');
        });

        Client.ready(function () {
            console.log('before DOM access');
            document.getElementById('cheese').innerHTML = 'cheese';
            console.log('after DOM access');
        });
    </script>
</head>
<body>
<div id="cheese">test</div>
</body>
</html>
Eli
  • 15,671
  • 4
  • 34
  • 48

2 Answers2

4

After some searching, this appears to be a known Mozilla bug: Errors thrown by handlers for custom events dispatched via dispatchEvent() are not logged properly in some versions of Firefox 3.x. This isn't a problem in your code, but in the browser implementation. If it's a real problem for you, you can wrap the handler in a try/catch block to identify and deal with errors:

document.addEventListener('readyEvents', function() {
    try { currentHandler() } catch (e) { console.log(e) }
}, false);

I have a jsFiddle here that demonstrates the problem with a simplified set of tests. Firefox correctly logs errors on handlers for built-in events like DOMContentLoaded and load, but misses the error when firing a handler for a custom event.

nrabinowitz
  • 52,936
  • 10
  • 139
  • 161
0

It's hard to get it right. See the jQuery source code and search for ready to see how it is implemented in a portable way. Keep in mind that you have to make sure that when you bind ready handlers after the dom is already ready then you have to call them straight away or else they won't be called at all. See also this question.

Community
  • 1
  • 1
rsp
  • 91,898
  • 19
  • 176
  • 156
  • I've seen this question before, and while it does go over some ways of creating document ready listeners, it doesn't solve my problem of Firefox not reporting errors generated inside of DOMContentLoaded from addEventListener. – Eli Feb 18 '11 at 19:20
  • See the jQuery source code. It's nicely commented and it works in Firefox. – rsp Feb 18 '11 at 19:25