Javascript: Introducing Using (.js)

by Jon Davis 12. April 2008 22:37

UPDATE: This is now managed on GitHub and this blog article is now obsolete. See you on GitHub!

https://github.com/stimpy77/using.js/


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

http://www.jondavis.net/codeprojects/using.js/

http://github.com/stimpy77/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:

<html>
  <head>
    <script type="text/javascript" language="javascript" src="using.js"></script>
    <script type="text/javascript" language="javascript">
      // your script here
    </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
  );

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.

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:

  1. using.register([json object]); // see using.prototype.Registration
    • object members, and the arguments for the compatible using.prototype.Registration prototype function, are both:
      1. name (string)
      2. version (string, format "1.2.3")
      3. remote (boolean, true if external domain; invoke requires callback)
      4. asyncWait (integer, milliseconds for imposed async; invoke requires callback)
      5. urls (string array)
  2. Registration chaining:
    • using
        .register("myScript", "/myscript.js")
        .register("myOtherScript", "/myotherscript.js").requires('myScript')
        .register("bob's script", "/bob.js");

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 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/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 half the tests fail on Safari now, and FF has inconsistent results especially with Firebug installed (actually it's not that bad, Safari 4 beta only fails the "retain context" test which is a minor issue, and FF fails about two tests)--but most of this Firefox's failures was 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/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 9/19/2012:

Using.js is now on GitHub! Thanks for all your comments, thumbs-up, and support!

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

kick it on DotNetKicks.com

Currently rated 4.5 by 22 people

  • Currently 4.454545/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Software Development | Web Development

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading




 

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

Jon Davis (aka "stimpy77") has been a programmer, developer, and consultant for web and Windows software solutions professionally since 1997, with experience ranging from OS and hardware support to DHTML programming to IIS/ASP web apps to Java network programming to Visual Basic applications to C# desktop apps.
 
Software in all forms is also his sole hobby, whether playing PC games or tinkering with programming them. "I was playing Defender on the Commodore 64," he reminisces, "when I decided at the age of 12 or so that I want to be a computer programmer when I grow up."

Jon was previously employed as a senior .NET developer at a very well-known Internet services company whom you're more likely than not to have directly done business with. However, this blog and all of jondavis.net have no affiliation with, and are not representative of, his former employer in any way.

Contact Me 


Tag cloud

Calendar

<<  May 2020  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar

RecentPosts