Ok, here it comes, any second now. It’s gonna be really cool … wait…hey… where are you going?
In today’s world of jQuery, Prototype and Mootools, the possibilities for rich user interaction expands by the day. You want that oh-so-nineties of a paginated search results to fade in and out? Done. You want that dusty old file input to be styled and totally awesome? No Problem.
First we’ll choose a javascript library, doesn’t really matter which one. Then we’ll put some placeholder on the page, maybe an empty div or, if we’re feeling really smart, we’ll put a fallback element for the non-Javascript crowd to use (do they still exist?). Next we’ll tag the placeholder with an id or class, your choice. Now all we have to do is write this really awesome Javascript initialization function that finds this element blows it away and replaces it with exactly one bazillion tightly packed elements with event listeners linked so tightly it looks like spaghetti. Beautiful, tasty DOM spaghetti. All wrapped up in Javascript too – so we never have to see it again. Finally, we’ll slap that initialization function onto body load and sit back and wonder at our creation.
Now we’re feeling pretty good right? We’ve got this new interaction that we’ve always wanted, and we’ve got a non-Javascript fallback for all 5 users that have Javascript turned off. Let’s view our page and gloat. Oh, what was that? The page loaded, I had no widget then a few seconds later, I have a widget. That was annoying. But don’t fret, let’s throw our initialization function in earlier. Let’s trigger it after the DOM is ready, but before the page is rendered.
Ah, that’s better. Now instead of seeing an ugly broken page first, I just stare at an entirely blank screen for a second or two. What’s going on? I just want the page to load like it did before but with this new (really awesome!) widget in place. Is that so hard?
Well, lets look at what is really going on here. (Disclaimer: I am no browser developer, so please give me a little leeway here in my explanation)
- The browser downloads the requested page,
- It parses the page to find assets it should download,
- It fires off threads (usually only 2 at a time) to download all the CSS, Javascript and Image files,
- Simultaneously, it is constructing the DOM and executing any inline Javascript,
- Once the Javascript files are downloaded, it executes them,
- Once all the files are downloaded and Javascript is loaded it renders the page,
… All that in milliseconds – pretty amazing huh?
Now, to implement our widget, let’s inject a step 5.5. As the library loads, it will fire off a piece of code to CONTINUOUSLY ask the browser “You done yet? You done yet? …. ” Finally the browser says “Yes, I’m done.” Now we’ll put in one more little tiny itsy bitsy step, 5.75, of creating one bazillion DOM elements all of which now need CSS styling and event listeners.
I’m sure the browser developers didn’t really try to optimize the other 6 steps in order to squeeze every tenth of a millisecond out of the page rendering time. I’m sure there’s room in there for my created-in-a-day Javascript to execute and have everything ready in time. … Really?
So what am I saying? Surely I’m saying that its a tradeoff – performance for features right? Absolutely Not! You just need to step back, think about the problem, and think about what needs to happen when and most of all, realize that using a Javascript library doesn’t mean that your old-school Javascript ways are outdated.
Start by taking that DOM spaghetti and throwing it directly there in your page. Go ahead, do it, it’ll feel dirty. Ok, now it’s not hidden behind Javascript, so clean that crap up. No really, it’s disgusting. Now throw your non-Javascript fallback in there and wrap it up in a container (hey, maybe even that same placeholder you used eariler). You may end up with something like this:
<div class="awesomeWidget">
.. fallback elements ..
<div class="widget" style="display:none">
.. spaghetti ..
</div>
</div>
See what we did? Now Javascript doesn’t have to create our spaghetti. It’s right there for all the world to see immediately. As soon as we let them. Remember the days of inline scripts and getElementById? They’re back!
<div class="awesomeWidget" id="awesomeWidget1">
.. fallback elements ..
<div class="widget" style="display:none" id="widget1">
.. spaghetti ..
</div>
</div>
<script type="text/javascript">
document.getElementById('awesomeWidget1').className += " processed";
document.getElementById('widget1').style.display = "block";
</script>
Now this is cake for the browser. It creates the DOM adds a class name and sets a style – all in time for page render. As an added bonus, we still have our non-Javascript fallback and enough CSS hooks to setup fallback styles as needed.
“But wait a second,” you say, “what about all the event listeners that make my widget work? I’m not writing all that stuff inline. I have a library and I want to use it!” Now I say, “Let your library skills loose!”. Now’s the time for the library to take over. You’ve rendered the page, the user doesn’t know that the widget doesn’t actually work yet – they’re still marvelling at it’s beauty. A second later, all the events are hooked up and your widget is ready to roll. You’re so awesome.