If you’re not yet up to speed on the drama with the new FF4 nightly (aka “minefield”) and how it affects the performance functionality (“preloading”) of LABjs, I encourage you to read that previous post.

Brief Summary

LABjs has a performance oriented feature (pretty much the 98% reason why LABjs even exists) called “preloading” which allows it to load all of a site’s scripts in parallel, but ensure their execution order (if needed/expressed) for dependency sake. Because the browsers all have different behavior on this topic, LABjs has a bunch of ugly gory stuff in its guts to smooth out the differences, using different tricks for different browsers.

The “trick” in question with the Mozilla line of browsers (FF, etc) is that <script> tags inserted dynamically into the browser (always have up to this point) preserved insertion-order for execution. As a matter of fact, that behavior is the most desirable behavior with respect to script loaders being used for improving site performance. But Mozilla has now dropped that behavior, and left us nothing in its place, meaning that LABjs’ performance functionality (again, the main and almost only feature) has been crippled for FF4 going forward.

Mozilla’s response

So, I wrote that post a couple of days ago to try and surface within the community the importance of this issue and try to get Mozilla involved in a discussion about how to resolve this difficult turn of events. The primary developer from Mozilla who is responsible for that change in behavior has now responded with a pretty lengthy explanation/admonition. I encourage you to go read that comment in full (almost as long as my original blog post). But I’m writing this post here to respond to the things said there. It’s long and involved and so needs its own post to do it justice.

Before I go into specific detail to address the points raised in that comment, I want to just give a general response as a summary to my feelings on what was said.

The comment goes into exquisite detail to chastise me for improper behavior regarding “UA sniffing” (and similar approaches), basically suggesting that the turn of events that have left LABjs in turmoil are basically expected and warranted given the approach that I took with how LABjs does its magic. The comment does have some cordial language to suggest that Mozilla is willing to further discuss possible ways forward, but the clear overall tone is that LABjs should never have done things the way it did, and that the primary use case that LABjs was designed to serve is dubious/questionable at best.


So let me just respond to that as a general tone of the comment.

LABjs has been around for about 15 months now. It’s been written up numerous times in Ajaxian.com, featured on many different blog posts (my own and several others), mentioned in a couple of different books, talked about relentlessly by me at JavaScript conferences around the world and through Twitter, endorsed by leading performance-optimization voices like Steve Souders, and now even powering JavaScript loading on some of the web’s biggest sites, like (new) Twitter, Vimeo, and Zappos. In addition to those big sites, I’m personally aware of hundreds of other sites of varying size/reach that are also using LABjs to load their scripts. I of course have LABjs running on a dozen or so of my own sites, including this blog.

In nearly 100% of the cases, including comments even in LABjs’ own source code and documentation on the site, I’ve proclaimed and admitted that the biggest “problem” that the web community has in terms of performance-oriented script loading is the browser fragmentation on how dynamic, parallel-loading of resources works. Script loading is not why LABjs exists. Script loading in a performance-savvy way is why LABjs exists. It’s an exceedingly complex task to try and load multiple scripts (of any sort and location, not just those specially prepared) in parallel, and ensure execution order, and do so with both local and remote scripts, and do so on-demand (that is, either during page load or later), and normalize that behavior across all browsers. To my knowledge, no other script loader has ever achieved such a wide-spread task as that.

I don’t own the credit for recognizing this problem existed. That belongs much more to Steve Souders. Steve is recognized as probably the most well-known and influential advocate for web performance that the web has today (and may ever have). In both of his books, “High Performance Web Sites” (HPWS) and “Even Faster Web Sites” (EFWS), he identified dynamic, parallel script loading as a very important use case that was not being well served on the majority of the web sites out there (both big and small).

I read both of those books diligently (and many times), and concluded that a generalized solution to performance script loading must be developed. In many ways, Steve is why LABjs was born. In fact, it was Steve who documented all the different fragmented behavior between browsers, and explored the various tools and tricks we had available to us to solve them. Unfortunately, he, like I, readily recognized that no such trick worked in all browsers. He presented code in EFWS (chapter 4 and 5) for how to begin addressing dynamic script loading, but admitted that the code was not general purpose enough for the masses and that more needed to be done.

Steve is the one who deserves credit for raising the awareness on the issues of dynamic parallel script loading, and for codifying the specific general use case that LABjs was designed to solve. In fact, he was instrumental in helping LABjs come to be, through several lengthy email threads, phone calls, in-person collaborations and brain-storming, etc.

You see, I didn’t develop LABjs in isolation in my basement. I went to one of the foremost authorities on these issues, and I studied what he had to say, and I worked countless hours to try and find a way to bring all the pieces together. In that process (over 5 months of development), I found a very delicate balancing act of tricks that solved the use case. Steve and I explored several possible alternatives, but eventually I decided that the way LABjs does things is the only currently workable solution that meets the goals of the project.

Fork you

And yes, this does require forking behavior between different browser families. But I’ve been a huge opponent of “UA sniffing” for years, including a rather lengthy disagreement comment-thread with Nicholas Zakas on the topic, as well as many others. So, I am fundamentally opposed to UA sniffing, and I absolutely detest anything that even smells like it. Of course I agree that feature-testing is the right way to go.

But there is no feature-test for the quirky behavior of different browsers with respect to how they load external resources dynamically, cache them, fire load events, etc. It’s one of those rare niche cases where feature-testing does not fit the bill. So the next best thing, in my opinion, is to use browser inference to fork the behavior between browsers. Essentially, this involves an indirect feature-test, by feature-testing for something known to belong only to one (or one set of) browser family(ies), and then based on that inference, relying on the previously observed behavior.

Is this foolproof? Hardly. It is a good idea? No, it’s a terrible idea. But in this case, no other even remotely acceptable alternative exists. It’s not an option, in my opinion, to simply not solve this use case now, as the other comment suggests. It’s not practical to have entirely different loaders for each browser, and force the web site to some how figure out (through server-side UA sniffing no doubt) which loader to use. UA sniffing AND browser-inference suck, but for LABjs, inference was the only option.

So, all this is to say, I understand the admonitions of the other comment against UA sniffing and related ilk. I don’t like them either. But I’m not some inexperienced script kiddie that has no clue. I’ve spent over a year trying to specialize in this area, and this is the best that I (and other far greater minds than me) could come up with. So while I appreciate the wisdom of avoiding such techniques when possible, I’d submit to you that it’s rather condescending to suggest that I simply was foolhardy and ignorant and that LABjs was destined for such failure as a result of my ill-advised approach. For the last 15 months, LABjs has been radically improving the web performance of hundreds or thousands of sites, and doing so carefully balanced on the tenuous tight rope of distinct browser quirks.

Call it what it is

The problem is not that LABjs relies on less-than-ideal practices to exploit quirks in various browsers. The problem is that the various browsers have persistently, for years, failed to find an agreement on how such resources can be loaded with performance optimization and flexibility as the primary concern. Even now, in that comment, the admission is clear: we can’t solve this use case with the current state of standards nor with the current state of web browser technology.

LABjs is a gap technology designed to fill the holes that browsers have carelessly left open. LABjs is designed to bring web performance optimization to web sites and scripts of all kinds right now, while we wait for browsers to catch up to that trend. The key assumption is of course that browsers will take note of that trend, and of the validity of the need, and will participate in the process. And I’ve done everything I can humanly do to advocate for that, in the shadows of greats like Steve Souders.

[deep breath]

OK, now that that’s off my chest, I need to address many other specific points in the Mozilla developer’s comment. But this post is already too long. So, I’m going to cut it here, and follow up with a second post (“part 2”), right away. So stay tuned.

[UPDATE] Please continue down the rabbit hole with Part 2 of Mozilla & LABjs.

This entry was written by getify , posted on Thursday October 07 2010at 09:10 am , filed under JavaScript, Performance Optimization and tagged , , , , , , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

4 Responses to “Mozilla & LABjs: The story unfolds”

  • Jeremy Dunck says:

    Obviously designing all scripts to define APIs and wait to be tied together (as Henri suggests) is a nice idea, but impractical – sites combine scripts from many different authors, and getting them to conform is boiling the ocean.

    Even so, I think pointing out specific breakage examples would be useful in the attempt to find a workable solution. Is it possible that newtwitter doesn’t rely on in-order execution?

  • getify says:

    I address the New Twitter issue in this follow up post that’s forthcoming shortly. But yes, you are correct, they currently have “preloading” disabled. But I am in regular contact with the Twitter dev team and they are intending soon to re-enable “preloading”, in which case their site would break in Minefield.

  • My comment was my comment, not a “Mozilla response” in the sense that it wasn’t vetted by anyone else before I posted it here. You write “Mozilla is willing”. More precisely, I am willing, but I’m using non-committal language, since I don’t have the authority to promise that anything in particular ships in any particular release of Firefox.

    I’m sorry about the tone of my comment. My bad excuse is that I was pretty annoyed at the tone of your post.

    And I’ve done everything I can humanly do to advocate for that

    Actually, you haven’t, since you didn’t get as far as posting a proposal to the W3C HTML WG’s mailing list, the W3C HTML WG’s Bugzilla or the WHATWG’s main mailing list.

    Let’s try to get by the “drama” aspect and focus on technical solutions. I’ll comment on technical stuff and on engaging with the HTML WG or the WHATWG on your “part 2” post.

  • getify says:

    Fair. Noted that it’s you and not Mozilla that’s engaging in this discussion.

    When I say “everything I can do” I mean that it’s everything *I* could have done. I don’t get paid or make money with this open-source project, so I don’t have open-ended backing to spend unlimited amounts of time on it. I’ve spent hundreds of hours on LABjs thus far, including lots of time just on this topic, and so the time I’ve spent is just about as much as I could have justified. I realize there are other doors I could have knocked on, but I simply didn’t have time to follow every trail. It’s unfortunate I obviously spent time on the wrong paths, but that was an honest attempt/mistake on my part.

    And for the record, I’m not trying to be offensive or attacking with these posts. I apologize if my tone came across that way. I agree that “drama” is not helpful to finding a resolution, so I do also hope we can set that aside and move forward.

Leave a Reply

Consider Registering or Logging in before commenting.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Notify me of followup comments via e-mail. You can also subscribe without commenting.