2

I was wondering if there is a javascript "include" function (similar to the one in python), and I was looking for something but couldn't find anything except $.load() and google.load().

So, I ventured out to create a script which could do that just for fun, so:

var include = function( lib ) {
// start with jQuery
    if(lib == "jquery") {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "http://code.jquery.com/jquery.min.js";
        script.defer = "defer"; // should I use script.setAttribute('defer', 'defer')?
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(script, s);
    }
}

And then, in a separate script:

include("jquery");
$("p").innerHTML = "Worked!";

But I got an error $ is not defined

Which makes sense, because the script is running before jQuery is loaded. So my question is, is there a way to make sure the include script runs before anything else ahead of it? I've seen callback solutions that look something like this:

include("http://code.jquery.com/jquery.min.js", function() {
    $("p").innerHTML = "Worked!";
});

But I do wonder if there is anything (like I proposed above) that's a little more neat.

Any help would be much appreciated!

Jace Cotton
  • 2,004
  • 1
  • 21
  • 38

3 Answers3

6

You're reinventing the wheel here: there's a vast number of the libraries/components doing basically the same job, but with more features. Check Asynchronous Module Definition API and RequireJS for a start.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • +1 Require.js has the added advantage of working in browsers as well as node.js – slebetman Sep 18 '13 at 22:52
  • "I've seen callback solutions that look something like this: `include("http://code.jquery.com/jquery.min.js", function() {$("p").innerHTML = "Worked!";});` But I do wonder if there is anything (like I proposed above) that's a little more neat." I know of all these libraries and stuff. Not trying to reinvent the wheel. Just trying to find (or making) something similar to python's. – Jace Cotton Sep 18 '13 at 22:57
  • 1
    @Jacedc If by "*neat,*" you mean synchronous/procedural and without the need for callbacks, then no. JavaScript doesn't yet have anything like coroutines where functions can pause execution and even `return` without blocking. [Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) will be close, but are an upcoming feature of ES6. Though, for some extendable environments, such as Node.js, you might find solutions, such as [fibers](https://npmjs.org/package/fibers). – Jonathan Lonowski Sep 18 '13 at 23:00
  • I see, but you ignore the golden rule of async JS: `'below'` doesn't mean `'after'`. And `include`-ing the external JS is asyncronous by default, as it's basically adding an element to DOM. – raina77ow Sep 18 '13 at 23:01
  • Ah. Okay. Just wondering... I'm trying to think if there's any possible way to include a script without posting a `script` element to an `html` element? That seems like a very conventional way to include a script. – Jace Cotton Sep 18 '13 at 23:06
  • Well, technically you can use sync AJAX call to get some code, then `eval` it, but that's really the road to nowhere (and I'm talking about _both_ sync AJAX and `eval`). And you'll be restricted to talking with your domain only (as opposite to injecting the ` – raina77ow Sep 18 '13 at 23:14
  • Well, I meant "conventional" as in, everywhere you look to inject an element via js, you use `document.createElement`, etc. But yeah, I guess they don't deserve the _label_. – Jace Cotton Sep 18 '13 at 23:18
  • See, most of the time when we're talking about `include`, we're actually talking about `including dependency` - and that's exactly what `AMD` in general, and RequireJS in particular, are about. Because the syntax sugar is only part of the problem: when you begin to manage dependencies, you have a lot more to think about on your side. – raina77ow Sep 18 '13 at 23:21
  • And regarding that python reference - are we talking about `import` or `execfile` here? These are [quite different beasts](http://stackoverflow.com/questions/11703327/python-import-vs-execfile). – raina77ow Sep 18 '13 at 23:23
  • See, that would be another thing. A javascript function similar to CSS' `@import` function. – Jace Cotton Sep 18 '13 at 23:24
0

Because of how JavaScript runs there is no way to do it much cleaner then that. You could have some sort of interval to load all files you need, so like this.

window.includeFiles = [];
function include(file){
   window.includeFiles.push(file);
}
function initialize(callback){
   for(var i = 0; i < window.includeFiles.length; i++){
      var script = document.createElement("script");
      script.type = "text/javascript";
      script.src = window.includeFiles[i];
      script.defer = "defer"; // should I use script.setAttribute('defer', 'defer')?
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(script, s);
      if((i+1)==window.includeFiles.length){
         callback();
      }
   }
}

Basically this will let you co like so:

include("http://code.jquery.com/jquery.min.js");
include("http://code.jquery.com/jquery.min.js");
include("http://code.jquery.com/jquery.min.js");
include("http://code.jquery.com/jquery.min.js");
include("http://code.jquery.com/jquery.min.js");
initialize(function(){
  //code ready
});

Only problem is it does not test network, witch can only really be done by checking if a function only available in the included library is available. Witch makes raina77ow's answer to use RequireJS a better solution.

Jordan Ramstad
  • 169
  • 3
  • 8
  • 37
0

The easiest way in my opinion is using head.js http://headjs.com/

head.js(
  "/path/to/jquery.js", 
  "/google/analytics.js", 
  "/js/site.js", function() {

   // Code that executes when all the scripts have been loaded

});
Zone6
  • 314
  • 2
  • 4