Skip to content
stimpy77 edited this page Sep 19, 2012 · 26 revisions

UPDATE 9/19/2012:

I have finally migrated Using.js from my 2008 blog post to GitHub for formally hosted management and community contributions. I want to thank everyone who previously downloaded and commented about using.js from my technical blog, giving me so many thumbs-up.

The current version as of this migration to GitHub remains v1.3.1 but this is expected to possibly change in the coming weeks.

About Using.js / Mini-Introduction

Using.js is a simple, very lightweight asynchronous script dependency loader for web browsers originally written in 2008 that allows a developer to write blocks of code in this fashion:

// register in a preceding script ..
using.register("jquery", true, "http://cachefile.net/scripts/jquery-1.2.3.js"); 

.. then consume synchronously ..

using("jquery"); // synchronously loads jQuery and de-registers jQuery from using 
$("a").css("text-decoration", "none");

.. or asynchronously ..

using ('jquery', function() {
    // do work using jQuery constructs
});

It documents dependencies within script and alleviates the need for fussing with injecting script dependencies on specific page headers. It also supports dependency trees, i.e. using('jquery-ui' ...) might depend upon jQuery, which would be loaded first.

Similar loaders exist such as RequireJS. I am not antagonistic towards those, use what you please, but I chose the name, syntax, and behavior of using.js because it has some level of parallel to coding conventions in other languages such as C#.

For more information about how to use using.js, please read the introduction below.


This is a GitHub Wiki transfer from Jon Davis's blog post in 2008: http://www.jondavis.net/techblog/post/2008/04/12/Javascript-Introducing-Using-(js).aspx

UPDATE 3/9/2010:

All of the modern browsers (Chrome, Webkit/Safari, Opera 10.5, IE8) except FF 3.6 now pass all the tests! I figured out what was wrong with Webkit and Opera not handling the "retain context" test properly. It turns out that window.eval() and eval() are not one and the same. The test now invokes eval() instead of window.eval(), and passes.

FF 3.6 still fails two tests: The "no callback" test (XHR is not behaving) and the multiple dependencies test; I'll look into it and follow up with Mozilla.

UPDATE 3/29/2009:

It is very unfortunate, guys, that the script loader in using.js doesn't really work as designed across all major browsers anymore. The demos/tests on the using.js page have erratic results depending on the browser--they all work fine in current Internet Explorer, but Safari 4 beta now fails the "retain context" test which is a minor issue, and FF fails about two tests--but Firefox's failures were not the case when using.js was implemented. It seems as though the browser vendors saw what using.js was taking advantage of as an exploit and started disabling these features.

Pretty soon I'm hopefully going to start looking at all the incompatibilities and failure points that have arisen over the last year to make using.js more capable. In the past I always took pride in building in standalone isolation from jQuery, but I'm using jQuery everywhere now, and jQuery has its own script loader, which apparently works or else it wouldn't be there (haven't tried to use it). That said, though, a port of using.js to jQuery's loader might make sense; the syntactical sugar and programming-think of using.js goes beyond just late script loading, it's more about dependency-checking and load history, and that part being just pure Javascript is NOT broken in the browsers.

UPDATE 3.1:

V1.3.1 should hopefully fix the "not enough arguments" error that some Firefox users have been having. I was never able to reproduce this, but I did discover after doing some research that Firefox supposedly expects null to be passed into xhr.send(). I guess some systems suffered from this while I didn't. At any rate, I'm passing null now.

UPDATE 3:

v1.3 fixes the using('url(..')) functionality so that a script loaded this way is remembered so that is not fetched again if the same URL is referenced in the same way again. This is the reverse of the using.register() behavior, where if a script is loaded its registration is "forgotten". Also made sure that multiple script URLs listed in using('url(..)', 'url(..)'), function(){}); is supported correctly.

If for some strange reason you want the script at the same URL to be re-fetched, try this unsupported hack that might not be available tomorrow:

using.__durls['http://my/url.js'] = undefined;

UPDATE 2:

With v1.2 I've added several new additional touches. Now you don't have to declare your subdependencies with using.register(), you can just say:

using('jquery', 'jquery-blockUI', function() { 
  $.blockUI(); 
});

This assumes that jQuery and blockUI have both been registered, the latter without the .requires('jquery') invocation.

That said, though, you don't even have to call .register anymore if you don't want to:

using('url(http://cachefile.net/scripts/jquery/1.2.3/jquery-1.2.3.js)', function() { 
  alert($.fn.jquery); 
});

There are also two new features that should work but I haven't written tests yet:

using.register([json object]); 

.. see using.prototype.Registration object members, and the arguments for the compatible using.prototype.Registration prototype function, are both:

  • name (string)
  • version (string, format "1.2.3")
  • remote (boolean, true if external domain; invoke requires callback)
  • asyncWait (integer, milliseconds for imposed async; invoke requires callback)
  • urls (string array)

Registration chaining:

using 
  .register("myScript", "/myscript.js") 
  .register("myOtherScript", "/myotherscript.js").requires('myScript') 
  .register("bob's script", "/bob.js");

UPDATE:

I just mostly rewrote using.js. Now with v1.1 you can now add subdependencies, like so:

using.register('jquery-blockUI', true, 
  'http://cachefile.net/scripts/jquery/plugins/blockUI/2.02/jquery.blockUI.js' 
).requires('jquery');

Basically what the new .requires() functionality will do is when you invoke using('jquery-blockUI'); it will also load up jquery first.


Original Introduction To Using.js

I'm releasing v1.0 of using.js which introduces a new way of declaring dependency scripts in Javscript.

https://github.com/stimpy77/using.js/ (originally: http://www.jondavis.net/codeprojects/using.js/)

The goals of using.js are to:

  • Seperate script dependencies from HTML markup (let the script framework figure out the dependencies it needs, not the designer).
  • Make script referencing as simple and easy as possible (no need to manage the HTML files)
  • Lazy load the scripts and not load them until and unless they are actually needed at runtime

The way it works is simple. Add a <script src="using.js"> reference to the <head> tag:

<!DOCTYPE html>
<html> 
  <head> 
    <script src="using.js"></script> 
  </head> 
  <body> .. </body> 
</html>

Then in your script, register your potential dependencies. (These will not get loaded until they get used!)

using.register("jquery", "/scripts/jquery-1.2.3.js");

Finally, when you need to begin invoking some functionality that requires your dependency invoke using():

using("jquery"); // loads jQuery and de-registers jQuery from using 
$("a").css("text-decoration", "none");

using("jquery"); // redundant calls to using() won't repeat fetch of jQuery because jquery was de-registered from using 
$("a").css("color", "green");

Note that this is only synchronous if the global value of using.wait is 0 (the default). You can reference scripts on external domains if you precede the URL in the using.register() statement with true and/or with an integer milliseconds value, or if you set the global using.wait to something like 500 or 1000, but then you must write your dependency usage scripts with a callback. (UPDATE: v1.0.1: Simply providing a callback will also make the load asynchronous.) No problem, here's how it's done:

using.register("jquery", true, "http://cachefile.net/scripts/jquery-1.2.3.js"); 
using("jquery", function() { 
  $("a").css("text-decoration", "none"); //async callback 
});

Oh, and by the way, using.register() supports multiple dependency script URLs.

using.register('multi', // 'multi' is the name 
    '/scripts/dep1.js', // dep1.js is the first dependency 
    '/scripts/dep2.js'  // dep2.js is the secon dependency 
  );

If you have bug reports or suggestions, please post comments here or e-mail me at jon@jondavis.net.