Req.js - javascript lazy-loading and dependency managment made easy

Written October 20. 2009, at 23:39 GMT.

Req.js is a simple, easy to use, full-featured library to handle lazy-loading and dependency management of Javascript. It's a standalone javascript library (no dependencies) and defines only a single object Req in the global scope.

The concept is loosely based on JSLoad with some ideas from Dojo.require and early YUI 3.0 alphas thrown into the mix.

It's stable and thoroughly tested in production environment on over one hundred websites since 2008.

Key Features:

  • Loads scripts asynchronously, with callbacks ...
    • Ensuring all scripts execute in the correct order.
  • Resolves and loads script dependencies.
    • Handles circular dependencies gracefully.
  • Avoids loading the same script twice.
    • Supports custom checks for the pre-presence of each script asset.
  • Allows mixing of local and remotely-hosted scripts.
  • Supports nested calls.
  • Allows for joining multiple assets into one "combo" HTTP request. (if supported by your server)

Also:

  • Highly configurable.
  • Cross-browser and no external dependencies.
  • Fast (no evals)
  • Tiny! (less than 1 kB gzipped)

Documentation

For a crash course in using Req.js, visit the demo page and inspect its source code.

Using the Req() function;

The library's core function, Req(), accepts any number of parameters.

The parameters may be a combination of:

  • String - Script URLs (either absolute or relative).
  • Function - Callback functions that run as soon as the preceding scripts have loaded.
  • Object - "Asset objects" that contain a script URL, charset info, dependency list, etc. (see below for more info).
  • String - "Asset object ID"s that refer to a previously defined "Asset object".

All parameters are processed (i.e. loaded or run) in the order they're passed.

Req() maintains a single processing queue, so nested and/or independently repeated calls to Req() add their list of requirements to the front of the master queue -- like so:

Req(A, B, C, function(){ Req(D, E); }, F);
Req(G, H, I);

// Will be processed in this order:
//   G, H, I,   A, B, C,   D, E,   F

However, an optional first parameter of true will instruct Req() to append those parameters to the master queue -- like so:

Req(A, B, C);
Req(D, E, F);
Req(true, G, H, I);

// Will be processed in this order:
//   D, E, F,   A, B, C,   G, H, I  

"Asset objects" and Req.assets

Req() keeps a database of "asset objects" to track which scripts have been loaded, what their dependencies are, etc.

Every URL you pass as a parameter is automatically turned into a simple asset object and stored in Req.assets.

var myurl = 'http://code.jquery.com/jquery-latest.js';

alert ( typeof Req.assets[myurl] );  // 'undefined'

Req( myurl, mycallbackfn );

var myAsset = Req.assets[myurl];
alert ( typeof myAsset );      // "object"
alert ( myAsset.toSource() );  // { src: 'http://code.jquery.com/jquery-latest.js' }

You can store asset objects under a friendly id/label in the Req.assets database, and then refer to the asset using that label...

Req.assets['jQuery latest'] = {
    src: 'http://code.jquery.com/jquery-latest.js'
  };

Req( 'jQuery latest', mycallbackfn );

Asset object properties

Asset objects may contain the following properties:

src (String)
The actual URL to the javascript file.
Relative URLs get normalized with Req.fixUrl and Req.baseUrl - while URLs starting with http(s)://, /, and ./ are left untouched.

check (Function)
Function that returns true/false that determine whether this resource has already been loaded (via other means, such as, direct <script> tags, etc.)

req (Array)
List of assets objects (or asset IDs or URLs) that this asset depends on -- each of which may depend on other assets, etc. etc.

onload (Function)
Callback function (onload event handler) to run when the asset has loaded for the first time. (Useful for running inits methods.)

charset (String)
Character encoding of the script file - e.g. "utf-8". (Useful for mixed charset environments on old MSIE browsers - which ignore HTTP charset headers sent by server.)

join (Boolean - default: false)
Can this asset be joined with others into a single HTTP request (see Req.joinUrl and Req.getJoinUrl properties below).

id (String)
Friendly id/name for the asset. (Only used when passing asset objects as parameters to the Req() function)

Req configuration properties

Req.urlToken (default: '%{s}')
Replacement pattern for inserting relative asset.src urls into _baseUrl and _joinUrl

Req.baseUrl (default: '')
URL string used for normalizing relative asset URLs
Example: 'http://www.server.com/scripts/%{s}.js' ... the first occurrence of Req.urlToken gets replaced by an asset's .src value. (If the urlToken is missing, it gets appended to the URL.)

Req.joinUrl (default: '')
URL string used for constructing "combo" URLs for joining multiple assets into a single HTTP request.
Example: 'http://www.server.com/join/?%{s}' (See notes for Req.baseUrl above.)

Req.joint (default: '')
String token to separate the script URL-stubs/labels as they get inserted into the joinUrl.
Example: '|' ... which might result in a combo URL similar to this: 'http://www.server.com/join/?script1|script2|script3|script4'

Req.joinLim (default: 1)
Minimum number of consecutive join-able items needed for joining to occur. (Otherwise fall back to normal single-file loading.)

Req.fixUrl (Function)
Function used internally to normalize asset .src values into real URLs.
Accepts a raw URL as a parameter, and returns a "fixed" (normalized) URL.
Default behavior: Relative paths are supplemented with the baseUrl. Other URLs are left untouched.

Req.getJoinUrl (Function)
Function used to get the combo URL-stub/label for the given asset.
Accepts an asset object as a parameter, and returns a combo URL-stub/label, that gets inserted (along with others) into the joinUrl.
Default behavior: Returns whatever comes after baseUrl in a normalized asset URL.

Req.assets (default: {})
Container (Object) for Asset objects (see info in a previous chapter).

Req.charset (default: '')
A default charset="" attribute value for the <script /> elements when they're inserted into the page.


Downloads & Links

Download:

Documentation home:

Source updates:


Copyright & Licensing

Copyright (c) 2009 Már Örlygsson and Hugsmiđjan ehf.

Dual licensed under a MIT license and GPL 2.0 (or above).


More like this: English Entries, Javascript.


Reader Comments (7)

  1. Dinesh replies:

    The Documentation home link is broken, the domain name does not have a period before net

    December 27. 2009 kl. 11:14 GMT | #

  2. Már replies:

    @Dinesh thanks. I fixed the link.

    December 28. 2009 kl. 10:29 GMT | #

  3. Rich replies:

    Req.js is very nice. Does everything I want. Question: I think I have a timing issue. Normal I would make jquery calls in the document onready to make sure elements are loaded.

    If in I do Req ('some-js', function), then that function seems to run before the DOM is ready.

    If I wait until DOM ready to start the Req(...), then I have to wait for all the js to load and user sees a lot of page flashing (as the layout and appearance javascript loads).

    Any thoughts on this appreciated. I hope I explain this OK.

    April 29. 2010 kl. 14:08 GMT | #

  4. Már replies:

    @Rich, the Req() function is completely agnostic to the readystate of the DOM. This means you may choose to either

    1. Place the script tag that calls Req at the bottom of your page's body.

    2. Call a 'domready' handler inside the callback function, like so:

      Req('some-js', function () {
          jQuery(function($){
              // your code runs when the DOM has loaded or
              // when `some-js` has loaded - whichever comes later
            });
        });
      

    However, as Req loads your some-js via script-tag injection the browser will continue to load and parse the DOM - which means 'domready' may fire before some-js has loaded.

    Thus, both methods may lead to a brief "Flash of Unstyled Content".

    My own favourite method for suppresing FoUC is to run a short script inside the page's head block, that writes a stylesheet tag with CSS rules to hide the flashing content.

    Then near the bottom of my javascript code - after I've parsed the DOM and hidden/removed the flashing content - I simply select the script element and delete it.

    Hope this helps.

    May 2. 2010 kl. 19:39 GMT | #

  5. Rich replies:

    I have gotten to spend more time with the script since my first post and it is a wonderful thing. Any trouble I had was something I didn't do right. What was confusing me for a while was: if there was a syntax error in one of my .js files, I would get an error saying that the function I was trying to call wasn't found. I thought the .js wasn't being loaded but it hit something it didn't like and didn't seem to tell me about it. Maybe there's less visibility when the .js gets loaded by Req verses a tag ? Anyway, it's great to be able to specify the dependencies and have things load up if needed. Good work. Thanks.

    I took some steps similar to what you mentioned for the FoUC and it is a lot better. I think what made my situation bad was: depending on whether certain content exists on the page being loaded I use Req to load .js files and in the callback I load related .css files. I load my page's style sheet last so even things like the page banner and navigation were coming out unstyled. It's hard to hide those things before they start to render.

    May 3. 2010 kl. 13:52 GMT | #

  6. Rich replies:

    If I load the demo page (http://mar.anomy.net/files/2009/10/reqjs/req-demo.html) in Safari 4.0.5, it loads OK. I hit refresh and it hangs. Do you see similar behavior? Thanks

    May 30. 2010 kl. 18:54 GMT | #

  7. Rich replies:

    Regards the last comment: I'm running Safari in Win7 x32.

    May 30. 2010 kl. 18:55 GMT | #

Ţessum svarhala hefur veriđ lokađ. Kćrar ţakkir til ţeirra sem tóku ţátt í umrćđunni.


 

Flakk um vefsvćđiđ



 

Nýleg svör frá lesendum

  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Req.js - javascript lazy-loading and dependency managment made easy)
  • Dinesh (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • Ada (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • notandi (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • Geir (Lausnin á efnahagsvandanum)
  • Jenný (Lausnin á efnahagsvandanum)
  • Óli Jens (Lausnin á efnahagsvandanum)
  • Már (Lausnin á efnahagsvandanum)
  • Kjartan S (Lausnin á efnahagsvandanum)

 

 

Yfirlit yfir ţetta skjal

(Atriđin í listanum vísa á ákveđna kafla ofar á síđunni.)