curl.js – yet another AMD loader [updated]
curl stands for Cujo Resource Loader since it’s an integral part of the re-engineering of cujo.js.
Version 0.3.2 is out! fork it!
What is an asynchronous loader?
Web apps, especially large ones, require many modules and resources. Most of these modules and resources need to be loaded at page load, but some may be loaded later, either in the background or “just in time”. They also need to be loaded as quickly as possible.
<SCRIPT> element in an HTML page. Similarly, CSS files are loaded via a
<LINK> element, and text resources are either loaded in the page or via XHR calls.
The problem with
<LINK> elements is that a browser must execute them sequentially since it has no idea if one may depend on another. It just assumes the developer has placed them in the correct order and that there are dependencies. (The term “synchronous loading” is used to describe this process since the elements are executed in a single timeline. I think “sequential” is a much better word, but nobody asked me.)
If there are no dependencies between two files, loading them sequentially is a waste of time. These files could be loaded and executed in parallel (i.e at the same time).
curl.js has lots of company. Other async loaders include LABjs, Steal.js, yepnope.js, $script.js, bdLoad, and RequireJS.
What is AMD?
AMD’s API focuses on two globally-available functions:
require() specifies a list of dependent modules or resources that must be loaded before running a set of code. This code resides in a callback function that is executed asynchronously, i.e. it runs later, not in the current “thread”. Specifically, it executes when all of the dependencies are loaded and ready.
Actually, the proposal says that the
require() function could have a different name — or could even be implemented differently. To keep with convention — and to better integrate with non-AMD CommonJS modules — we’re using
curl() is also an alias to
It’s more important that the
define() method be consistent. This is the method that tells the loader what modules have been loaded by a script.
define() also specifies a list of dependencies and a callback function that defines and/or creates the resource when the dependencies are ready. Optionally,
define() also takes a name parameter, but this is mainly for build tools and optimizers.
AMD’s API also helps code reuse by providing compatibility with CommonJS server modules. AMD-compliant loaders support the same
Not all async loaders are AMD-compliant. Of the list above, only the following are AMD-compliant:
(there are a few others in that google spreadsheet link)
The beauty of AMD loaders is their ability to remove the drudgery of manually managing dependencies. Since all dependencies are listed within the modules, the loader will ensure that everything is loaded into the browser — and in the right order.
Even better: the modules are always loaded in parallel without blocking the loading process of the rest of the page.
So how can I get my hands on curl.js?
curl.js is up on github! Fork it or clone it to your local disk and check out the Very Simple Example in the README file.
At the time of this blog post, curl.js is at version 0.3.1 and is not 100% compatible with CommonJS Modules 1.1 (only missing the
module parameters). However, I am currently unit-testing 0.3.2, which is 100% compatible!
Compared to other AMD loaders, curl.js is tiny. At 4.5KB (2.1KB gzipped using Google Closure Compiler), it’s half the size of the others. It also employs some wicked cool techniques using promises.
Version 0.3.2 will be ready for production use, despite the zero-dot version number. Please check it out and let me know what you think!