I still have one concern about Dojo
Category javascript performance
In anticipation of the release of Domino 8.5, I've been familiarizing myself with Dojo, which thus far has mostly consisted of identifying syntactical differences between it and other frameworks I'm already familiar with. My conclusion is that it's not all that different; one of the two most noticeable differences is the inclusion of additional parameters in the actual markup to indicate to Dojo how certain tags should be handled. In this example, for instance, the author adds to a div a parameter of "dojoType" with a value of "dijit.form.DropDownButton": this tells Dojo that, upon load, it should render something that looks and behaves like a drop-down button where that div is placed, using the innerHTML of the first span it contains as the label for the button. That's fine. I like that: you can determine from the markup how the page should "look" to the user. Granted, I'd rather see them take a semantic approach, but meh.
The other difference, however, is simultaneously cool and troubling. Every "official" example or demo I've seen includes just the base dojo.js file in the markup, then in a custom script loads in everything else the page will need via the dojo.require() syntax. In the previously linked example, for instance, there are function calls similar to the following:
dojo.require("dijit.Dialog");
Why? Because the base Dojo file only includes core functions - such as XHR, array extensions, and the like... as well as a capacity for dynamically loading other script files. Rather than load the entire framework and only use a small fraction of its capability on any given page, dojo.require() allows you to tell the browser precisely what you need and, therefore, only load that. This should enhance performance by minimizing the amount of data the browser needs to download in order to provide the functionality your page requires...
...in theory. In practice, not necessarily. Some have compared this dynamic loading to Java's import statement, and there are certain similarities. When compiling a Java application, import tells the compiler which classes to load, and excludes everything else. Dojo also uses namespacing to provide clarity regarding what is being included. But the difference is that Java is compiled, and JavaScript is interpreted: when you click Save in Eclipse, therefore, it "builds" everything: the resulting class file is aware of everything it needs to be in order for your application to run. A web page, on the other hand, must download each file individually. As I'm sure I've mentioned before (ah, yes, here it is), a powerful way to improve the performance of any web page is to minimize the number of HTTP requests; although Yahoo's list of recommendations keeps growing, that's still their number one guideline. If, for example, you have 10 script files that are 20 KB each, and one 200 KB file that combines all of them, the browser will load the 200 KB file faster than it would load the 10 separate files, even though the same amount of data is exchanged. That's the primary reason I wrote JSFactory and still use it nearly every day (especially lately). Dojo, on the other hand, takes the opposite approach: I added the Dialog example to an application I'm working on (and no other Dojo functionality), and the result was 35 separate HTTP requests, ranging from 3 KB to a mere 84 bytes. I kid you not: one file it loaded was common.js:
({"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"})
That's the entire script file. That's ridiculous. I'm logged into Domino, so the LtpaToken cookie sent back to the server via a request header allowing it to decide whether or not I have access to that file is larger than the content sent back once it determined that I did have access to it. Dojo has a reputation for being slow, but it's mostly undeserved: I've found that, once the page has loaded, dijit responsiveness is roughly equivalent to widgets in other frameworks. But this dynamic loading that (I assume) is intended to streamline initial page load, in fact, has the opposite effect, and by the time the user is allowed to interact with the page, the impression of "slow" has already been established.
So what's a developer to do? Well, it's easy, actually... again, in theory. Dojo includes a custom build packaging system. So all you have to do is have a copy of the Dojo library on your local computer, write a build profile that designates which modules you would otherwise be importing via dojo.require() statements (heck, you can even include your own custom script files), and then run a shell script (or a batch file, for the majority of you who would be running this from Windows... though the tutorial assumes Linux and mentions the Windows option as an afterthought), and voila: you have a single (combined, compressed, and otherwise optimized) script file that you can then reference in your web page... assuming you've placed it somewhere on the server (either by adding/updating a file resource in a Domino database or moving it directly into the server's folder structure). Sounds a lot like JSFactory, doesn't it (other than automating the step where it updates your Domino file resource)?
But there are a couple minor caveats. First, you must have a copy of the Dojo source (which you can download here), not the built version that's automatically included on the server with Domino 8.5; second, any time the mixture of modules you need (or the content of any custom script) changes, you have to run the build again, and update the server's copy of the file. In other words, this can become very tedious.
Here's what I'd recommend:
In anticipation of the release of Domino 8.5, I've been familiarizing myself with Dojo, which thus far has mostly consisted of identifying syntactical differences between it and other frameworks I'm already familiar with. My conclusion is that it's not all that different; one of the two most noticeable differences is the inclusion of additional parameters in the actual markup to indicate to Dojo how certain tags should be handled. In this example, for instance, the author adds to a div a parameter of "dojoType" with a value of "dijit.form.DropDownButton": this tells Dojo that, upon load, it should render something that looks and behaves like a drop-down button where that div is placed, using the innerHTML of the first span it contains as the label for the button. That's fine. I like that: you can determine from the markup how the page should "look" to the user. Granted, I'd rather see them take a semantic approach, but meh.
The other difference, however, is simultaneously cool and troubling. Every "official" example or demo I've seen includes just the base dojo.js file in the markup, then in a custom script loads in everything else the page will need via the dojo.require() syntax. In the previously linked example, for instance, there are function calls similar to the following:
dojo.require("dijit.Dialog");
Why? Because the base Dojo file only includes core functions - such as XHR, array extensions, and the like... as well as a capacity for dynamically loading other script files. Rather than load the entire framework and only use a small fraction of its capability on any given page, dojo.require() allows you to tell the browser precisely what you need and, therefore, only load that. This should enhance performance by minimizing the amount of data the browser needs to download in order to provide the functionality your page requires...
...in theory. In practice, not necessarily. Some have compared this dynamic loading to Java's import statement, and there are certain similarities. When compiling a Java application, import tells the compiler which classes to load, and excludes everything else. Dojo also uses namespacing to provide clarity regarding what is being included. But the difference is that Java is compiled, and JavaScript is interpreted: when you click Save in Eclipse, therefore, it "builds" everything: the resulting class file is aware of everything it needs to be in order for your application to run. A web page, on the other hand, must download each file individually. As I'm sure I've mentioned before (ah, yes, here it is), a powerful way to improve the performance of any web page is to minimize the number of HTTP requests; although Yahoo's list of recommendations keeps growing, that's still their number one guideline. If, for example, you have 10 script files that are 20 KB each, and one 200 KB file that combines all of them, the browser will load the 200 KB file faster than it would load the 10 separate files, even though the same amount of data is exchanged. That's the primary reason I wrote JSFactory and still use it nearly every day (especially lately). Dojo, on the other hand, takes the opposite approach: I added the Dialog example to an application I'm working on (and no other Dojo functionality), and the result was 35 separate HTTP requests, ranging from 3 KB to a mere 84 bytes. I kid you not: one file it loaded was common.js:
({"buttonOk":"OK","buttonCancel":"Cancel","buttonSave":"Save","itemClose":"Close"})
That's the entire script file. That's ridiculous. I'm logged into Domino, so the LtpaToken cookie sent back to the server via a request header allowing it to decide whether or not I have access to that file is larger than the content sent back once it determined that I did have access to it. Dojo has a reputation for being slow, but it's mostly undeserved: I've found that, once the page has loaded, dijit responsiveness is roughly equivalent to widgets in other frameworks. But this dynamic loading that (I assume) is intended to streamline initial page load, in fact, has the opposite effect, and by the time the user is allowed to interact with the page, the impression of "slow" has already been established.
So what's a developer to do? Well, it's easy, actually... again, in theory. Dojo includes a custom build packaging system. So all you have to do is have a copy of the Dojo library on your local computer, write a build profile that designates which modules you would otherwise be importing via dojo.require() statements (heck, you can even include your own custom script files), and then run a shell script (or a batch file, for the majority of you who would be running this from Windows... though the tutorial assumes Linux and mentions the Windows option as an afterthought), and voila: you have a single (combined, compressed, and otherwise optimized) script file that you can then reference in your web page... assuming you've placed it somewhere on the server (either by adding/updating a file resource in a Domino database or moving it directly into the server's folder structure). Sounds a lot like JSFactory, doesn't it (other than automating the step where it updates your Domino file resource)?
But there are a couple minor caveats. First, you must have a copy of the Dojo source (which you can download here), not the built version that's automatically included on the server with Domino 8.5; second, any time the mixture of modules you need (or the content of any custom script) changes, you have to run the build again, and update the server's copy of the file. In other words, this can become very tedious.
Here's what I'd recommend:
- Use Aptana (or your favorite JavaScript IDE; mine is Aptana for various reasons, one of which is that it supports auto-suggest for Dojo and several other frameworks) to write all custom JavaScript code that doesn't need to be generated dynamically. This keeps your source in a folder the Dojo build script can reference.
- Create a build profile that includes a reference to all of the Dojo modules that you're using - plus your custom code - which you'll update whenever that module list changes. For bonus points, write an Aptana script that monitors all files in your project for save events and updates the dependency list automatically based on which dojo.require() statements it finds.
- If you're running Windows, place a .bat file for each project on your desktop that cd's to the Dojo build scripts folder and runs the build batch using your profile for the project. If you're using the Desktop toolbar, you can then update the build from anywhere with two clicks: one to view your desktop as a menu, and one to launch the build process.
- Create a project profile in JSFactory that includes just the build output file as the source. There's no need to specify a minified output, since Dojo will already have minified the source, but if you've configured your server to support GZIP, you can enable that option. Then with a single click in your Notes 8 sidebar, you can update the desired file resource element with the contents of your latest build.

Comments
Here's the thing: what we really know from this is that browsers are lousy compilers. I mean, seriously -- isn't it the most basic of source-code management rules that you don't care what order libraries are loaded in or when variables are declared, because at compile-time, you're going to move all that stuff into the right place.
Well, the basic strategy of the browser to render content while it's still loading has fundamental flaws in the Web 2.0 world. At the very least, we should be able to override that behavior, and be quite certain that we're looking at a very different page while some rendering process is still loading.
Ironically, Dojo DOES do this, albeit not in a particularly amazing fashion.
Anyway -- I'm not at all clear why it's incumbent on the developer of an application to optimize the behavior of the runtime client. That really should be the responsibility of Mozilla or Safari or Opera or whatever, right?
Posted by Nathan T. Freeman At 12:57:15 AM On 12/24/2008 | - Website - |
Trouble is, none of them has seriously revisited the flow/parse/paint portion of the underlying browser model in yeeeears ([sic] for dramatic effect). Whenever prompted, Doug Crockford can go on and on about this... he was one of the first (if not the first) proponent of putting script tags at the bottom of the body and CSS links at the top of the head, specifically for that reason: the sooner the browser knows the color, size, decoration, position, etc. of each element, the more rapidly it can proceed with the paint step; conversely, every time script is encountered, the browser (any browser, because they all share this limitation) yanks the lever to shut down the conveyor belt so that nothing will interfere with interpretation and execution of that script.
<rhetorical>How many different implementations are there of an "onDOMReady" function?</rhetorical> Ironically, because each browser has continued to optimize its JavaScript engine, while comparatively neglecting its rendering engine, we literally have to slow down execution of any script that interacts with the DOM (as opposed to simply defining objects/functions for the user to interact with later) until the script engine is able to determine that the DOM parser has finally gotten around to doing its job. Reminds me of all the utilities that exist to slow down a CPU so that we can still play old DOS games that became unplayable once computers became "too fast": just like I can no longer play my favorite pinball game from childhood without underclocking the processor, because the ball's already gone before I have time to hit the space bar, JavaScript is now parsed so quickly that, unless I incorporate something to delay execution, I can't modify/remove DOM members during page load, because the script not only stops DOM parsing to be interpreted, but it's too fast - the div I'm trying to move from the element Domino insists on rendering it inside if it's generated by a repeat control to where it really needs to be for Dojo to make it draggable doesn't exist yet... except in the hopes and dreams of children everywhere. Sorry, weird mood today.
Posted by Tim Tripcony At 10:18:30 AM On 12/24/2008 | - Website - |
AOL used to host a build with all of the commonly used modules, and recommended that sites which wouldn't need all that code should use the Dojo build process and just host their own. After 0.4.2, they switched to just hosting the base Dojo file (like Google does). So you're in the same boat with a CDN: you're loading the library piecemeal instead of issuing a single HTTP request to get everything the user needs.
Perhaps worthy of note is that this is the same reason why CSS sprites are all the rage these days:
{ Link }
Say, for example, you have 50 different 16x16 icons for your JS-based WYSIWYG HTML editor. You could keep each as a separate graphic file, which at first glance would be preferable, because they're all small. But because that would require the browser to issue 50 separate HTTP requests, it's better to create a single graphic that is essentially all of them stuck together, and then use CSS to determine which portion of the combined graphic to display where. While this might only be slightly faster, the user perception will be that it loads faster, because all the icons appear at once instead of them showing up two by two, fractions of a second apart.
Posted by Tim Tripcony At 04:37:14 PM On 11/21/2008 | - Website - |
It turns out the Google CDN allows https. I'm a happy camper now.
Example of https to google >> { Link }
Posted by Jake White At 04:34:01 PM On 11/21/2008 | - Website - |
Posted by Erik Brooks At 03:50:05 PM On 11/21/2008 | - Website - |
The js files load up from local-ish sources so that latency of multiple requests (while still an issue) isn't the killer it can be when accessing files from the Notes application server. I've done zero research to find out, but it would be interesting to have an option in 8.5 to use the CDN rather than the "built in" copy of Dojo.
Google js apis >> { Link }
AOL CDN >> { Link }
Posted by Jake White At 03:04:13 PM On 11/21/2008 | - Website - |
Posted by Matt White At 01:51:49 PM On 11/21/2008 | - Website - |
Posted by nick wall At 09:28:06 AM On 11/21/2008 | - Website - |
Domino for Aptana...!!! I've got nothing to do with this guy or his product, but overnight, this changed the way I code my css and JS. I have been using other frameworks (Ext JS), but must get to grips with Dojo.
Posted by Nick Wall At 09:26:04 AM On 11/21/2008 | - Website - |
The biggest adoption problem is the lack of documentation, and the biggest "gotcha" problem is the custom build process that you describe. You simply MUST do it for production, and it's actually considered standard practice by the community. They just don't scream it from the rooftops like they should, and so newcomers try the usual "dojo.require()..." and end up thinking that Dojo is chunky and slow.
FYI, the 8.5 server betas did NOT have custom layer builds of the Dojo widgets used by Domino. This was causing massive page loads (and especially horrible load times on high-latency connections).
I posted about it in the 8.5 beta forum here:
{ Link }
Supposedly they've tackled it for the release version.
Posted by Erik Brooks At 11:57:09 AM On 11/21/2008 | - Website - |