The way JavaScript is handled: A call to action
I’ve been doing a lot of thinking lately about the problems I repeatedly run into using JavaScript in browsers. While JavaScript has come a long way in terms of how we design and use it on the client, the way that browsers deal with JavaScript hasn’t changed fundamentally since Netscape 2.0 introduced it in the first place. Sure, we use a type attribute instead of language, but really nothing has changed and this has led to problems.
The number one problem I see is the way we are required to attach event handlers to elements. Look at how CSS works: the style definitions are loaded ahead of time and as an element appears on the screen that matches a particular pattern, that style is automatically applied. You don’t need to wait until the page has been completely loaded and then apply a style specifically to an element; the browser does this for you.
When we want to attach an event handler to an element, there are two ways to do it: 1) add an attribute in the HTML code, which is not recommended, or 2) add the event handler yourself using JavaScript. Since the first option is frowned upon because it too tightly couples the data and the behavior, we’re left with the second, which means you need to attach the event handler after the element is available. To do so, you’ll either use onload or some alternative to DOMContentReady. Though this decouples the layers better, there is a lag. It’s possible for the user to start clicking around on the page and have nothing happen because the event handlers haven’t been added yet. I think we can do better.
What if attaching events to elements worked just like assigning styles? What if you could tell the browser that a particular element should have a specific set of event handlers as soon as the element becomes available? This would free you from ever needing to call addEventListener() or its equivalent; there would be no lag and you’d still maintain loose coupling between HTML and JavaScript. In fact, there’s already (non-standard) implementations of this, expressed in Microsoft’s DHTML Behaviors, which allow you to use the behavior property in CSS to specify how elements should behave, and Mozilla’s XBL, which is how the standard elements of Firefox’s interface are defined (and may also be used in HTML). While neither of these are suited for building modern web applications (Microsoft’s implementation requires too many HTTP requests, Mozilla’s is far too abstract), this is where I believe JavaScript support in browsers needs to go.
Being able to specify behaviors in this way brings to light another problem with how browsers deal with JavaScript: they load each file synchronously, blocking other requests and preventing the page from rendering until the file has been completely downloade, parsed, and interpreted. Microsoft was nice enough to implement the defer attribute on the <script/> element, but that just defers the downloading and evaluation until after the page has been rendered. So basically, the options we have are either parse and evaluate now or parse and evaluate later, and neither of those is sufficient.
JavaScript files are loaded synchronously because of dependencies, file2.js may depend on stuff in file1.js to work properly. These dependencies need to be respected, but I think there’s a better way to do it. What if instead of blocking the browser while downloading a JavaScript file, we had a way of saying, “hey, this file just has behaviors that aren’t needed until the user starts interacting, so don’t worry about evaluating this code quite yet.”? Basically, make it work like style sheets currently work. Don’t stop the presses just to download and parse the file, keep going, download the file and add it to a global parse tree. Each time a new JavaScript file is loaded, fire off a request and then continue on, assembling the entire bunch of code behind the scenes as the page continues to load.
The Web has been around for a decent amount of time now and the art of building web applications has developed significantly enough that it’s time to start asking if the tools we currently have are good enough. Most people will say “no,” but can’t express what they’d like to change. So here I am, putting my foot down and saying this is what I’d not only like to see changed but also that I believe this has been a long time coming. We’ve become better JavaScript developers but the browsers remain as dumb as ever in how they handle JavaScript. It’s time for a change.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




5 Comments
Now if only we could get people to stop using document.write. This is the real reason why deferred evaluation of JS code won’t happen: a script tag embedded in the BODY of the page may have code that writes to the DOM as it is parsed. Let’s start with Google: perhaps one of the most notorious practitioners of bad web practices. Google ads are built on document.write; we’ll need a practical alternative, which, as you suggest, should come in the form of execution on element load – which is what YUI, in part, does with Event.onContentReady and JS libraries like jQuery and Behaviors shoot for with their CSS selector engines. The problem that we’re facing, though, is that browser vendors never exposed their built-in CSS selector engines to the DOM, thus requiring slow, DOM-walking implementations in JS. Bring in a native getElementsBySelector and allow execution on element load (so a script can manipulate the DOM as it’s loaded), and we’re close to a workable solution.
David Golightly on October 20th, 2007 at 1:57 pm
Regarding your first suggestion: have you seen this working draft of behavioral extensions to CSS? http://www.w3.org/TR/becss/
Alexei Gorkov on October 20th, 2007 at 3:56 pm
Your suggestion and our(JS Developers) need is brilliant, and long over due. Too many times I’ve run into the parsing issue, with no solution other than, "well, that’s just the way it works…" It’s high time we put the ‘Edsel’ way of doing things to rest and upgrade the way JS is handled in the Browser.
Oh, and the Sox are up 10-1 4th!
ryan on October 20th, 2007 at 10:17 pm
I like creating elements *with* javascript because it avoids all the getElementById mappings.
This is perhaps tacky and undesirable for content based pages where elements are finite and the goal is to make sure search engines indexes the content, but for a page that is a tool, I like creating the markup elements using javascript, and attaching to those elements their corresponding conceptual object from the object oriented model that I’ve designed. During an element’s event, I’m able to access that elements corresponding object via the <i>this</i> keyword.
When you attach an event handler to an element that originated in your javascript, the user won’t be able to trigger that event until you’ve attached it to the DOM. However, granted, you can’t attach it to the DOM until onload, but that will happen immediately if you’re generating elements with javascript because your markup document starts out extremely lean.
Lonnie Lee Best on October 21st, 2007 at 11:05 am
@David – you’re right, document.write() is what’s currently holding us back right now. That is a problem that needs to be solved so we can move this along.
@Alexei – I hadn’t seen that! Unfortunately, my trust in the W3C is quite shakey, so I’m not sure if this will evolve correctly. I’ll definitely stay tuned, thanks for the link!
@Ryan – thanks for the game update, I was on a plane when it was happening.
Nicholas C. Zakas on October 21st, 2007 at 2:38 pm
Comments are automatically closed after 14 days.