3

I spent the better part of last month beating my head against the wall before I came up with an easy way to dynamically load, and chain together HTML canvas classes which are stored on the server, but, obviously, initialized on the client (harder than it sounds when the ordering is important in an asynchronous environment).

I was wondering if someone could help me find a way to load simple javascript scripts. Lets define a load('foo.js') function which instructs the client to load script foo.js from the server and execute it as javascript code.

Given the three files, stored on the server:

A.js

a = 10;

B.js

load('A.js');
b = a + 10;

C.js

load('B.js');
c = b + 10;

If the client issues the command load('C.js'); what's the easiest/most reliable way to implement this. One idea I had was to scan the code serverside and return all the scripts at once. This requires the minimal amount of php requests. However, if the client has already requested C.js before, the script should exist client side, and this would be inneficient, especially if C.js and all its dependent files are large. Another option I considered was to wrap all of these serverside scripts in an object like so, for C.js above:

{
  depenencies: ['B.js'] ,
  code : 'c.age = b.age + 10;'
}

I just don't know how to 'pause' execution of script C.js after the load('B.js') statement, and then resuming it after B.js has been loaded.

EDIT Thanks to redsqaure for suggesting yepnope and requirejs. Unfortunately, I do not like them for several reasons. For one, requirejs is difficult (I am sure I will come under criticism for this one). My main gripe with this is that, if it is so difficult to learn, I might as well recreate it myself, learning it in the process, AND having greater control over it. Second, it requires you to change your style of writing. Switching to Dojo and having to use dojo.declare("ClassName", [ParentA,ParentB], {...}); to declare classes is one thing, but wrapping every snippet of code in require(['A','B',...], function(){}); is another. Finally, I don't know how simple it will be to instruct where to look for files. I want the user to be able to define a 'PATH' variable server side, and have the search occur in each of the folders/subfolders of the 'PATH'

puk
  • 16,318
  • 29
  • 119
  • 199

2 Answers2

1

Depends on how optimized you want it to be. Either you can go the route of synchronous XHR or use a callback (async and recommended). If you were to go the second route your code would look something like:

// Say C.js is dependent on A.js and B.js..
load(["A.js","B.js"], function() {       
     // code goes here    
});

EDIT

Taking a second look after you feedback what you want is somewhat possible, but would be brittle and hard to write in javascript. Below i have a sample/untested implementation of a dependency loader where a file can only have one call to load("file.js") possible. This would be more complex for multiple possible dependencies. Also I'm assuming these files are coming from the same domain.

// Usage: load("A.js")
// A.js -> B.js -> C.js
window.load = (function() {

    var loaded = {};

    return function(str, /* internally used */ callback) {

        if(!loaded[str]) {

            loaded[str] = true;

            $.get(str, function(data) {
                var matches = data.match(/load\(['|"](.*)["|']\)/);

                if(matches.length > 1) { // has deps

                    window.load(matches[1], function() {
                        window.eval(data);
                        if(!!callback) callback();
                    });

                } else { // no deps
                    window.eval(data);
                }

            });

        } 
    }
})();
Art
  • 5,864
  • 3
  • 30
  • 32
  • [from my understanding](http://stackoverflow.com/questions/2088318/is-there-any-reason-to-use-a-synchronous-xmlhttprequest) synchronous Ajax calls are almost completely useless – puk Sep 02 '11 at 07:05
  • your example is somewhat like my current approach, however, it would be difficult to do `load(['A.js','B.js',...,'Z.js'], function(){});`, therefore, each script would have to be reimplemented as `load(...)` and the whole thing becomes incredibly complicated. This callback seems really useful to me, like the image `onload()` callback. I'm surprised support for it doesn't exist. – puk Sep 02 '11 at 07:07
  • @puk, yes they are useless, but if you want to stop evaluation like the question asks either you use a callback or you block until you have the resource, so actually relevant here. – Art Sep 02 '11 at 07:31
  • @puk why would it be difficult to do that? you need to declare the dependencies one way or another, if you have 27 of them, then you will have to list them all out anyway. – Art Sep 02 '11 at 07:34
  • what I was looking (hoping) for was a simple `include` statement like in C (yes, I know it's a client side compiled language). I fear my code is going to turn into a nested ball of string. A Dojo definition inside a load statement does not look very pretty. – puk Sep 02 '11 at 07:39
  • arturnt, that is exactly what I wanted. I'll give it a shot implementation-wise. Thanx – puk Sep 02 '11 at 21:57
1

Why not look into a script loader like yepnope.js or require.js

redsquare
  • 78,161
  • 20
  • 151
  • 159
  • I looked at require.js a while back. I based my require function off of it. It will do what I need here, but sadly it does not do it in a clean way. – puk Sep 02 '11 at 07:22