views:

270

answers:

4

Is it possible to call in a .js file synchronously and then use it immediately afterward?

<script type="text/javascript">
    var head = document.getElementsByTagName('head').item(0);
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', 'http://mysite/my.js');
    head.appendChild(script);

    myFunction(); // Fails because it hasn't loaded from my.js yet.

    window.onload = function() {
        // Works most of the time but not all of the time.
        // Especially if my.js injects another script that contains myFunction().
        myFunction();
    };
</script>

This is simplified. In my implementation the createElement stuff is in a function. I thought about adding something to the function that could check to see if a certain variable was instantiated before returning control. But then there is still the problem of what to do when including js from another site that I have no control over.

Thoughts?

Edit:

I've accepted the best answer for now because it gives a good explanation for what's going on. But if anyone has any suggestions for how to improve this I'm open to them. Here's an example of what I'd like to do.

// Include() is a custom function to import js.
Include('my1.js');
Include('my2.js');

myFunc1('blarg');
myFunc2('bleet');

I just want to keep from having to know the internals too much and just be able to say, "I wish to use this module, and now I will use some code from it."

+1  A: 

This looks like a decent overview of dynamic script loading: http://unixpapa.com/js/dyna.html

morgancodes
+4  A: 
Pointy
unfortunately it's not cross-browser.
galambalazs
Really?? Who doesn't fire a "load" event when a script is loaded? **Wait** - don't tell me.
Pointy
+1  A: 

Asynchronous programming is slightly more complicated because the consequence of making a request is encapsulated in a function instead of following the request statement. But the realtime behavior that the user experiences can be significantly better because they will not see a sluggish server or sluggish network cause the browser to act as though it had crashed. Synchronous programming is disrespectful and should not be employed in applications which are used by people.

Douglas Crockford (YUI Blog)

Alright, buckle your seats, because it's going to be a bumpy ride. More and more people ask about loading scripts dynamically via javascript, it seems to be a hot topic.

The main reasons why this became so popular:

  • client-side modularity
  • easier dependency management
  • error handling
  • performance advantages

About modularity, it is obvious that managing client-side dependencies should be handled right on the client side. If a certain object, module or library is needed we just ask for it and load dynamically.

Error handling, if a resource fails we still got a chance to block only parts that depend on the affected script, or maybe even give it another try with some delay.

Performance, has become a competitive edge between websites, it is now a search ranking factor. What dynamic script can do is mimic asynchronous behavior as opposed to the default blocking way of how browsers handle scripts. Scripts block other resources, scripts block further parsing of the HTML document, scripts block the UI. Now with dynamic script tags and its cross-browser alternatives you can do real asynchronous requests, and execute dependent code only when they are available. Your scripts will load in-parallel even with other resources, the rendering will be flawless.

The reason why some people stick to synchronous scripting is because they used to it. They think it is the default way, it is the easier way, and some may even think it is the only one.

But the only thing we should care when this needs to be decided concerning an applications's design is the end-user experience. And in this area asynchronous cannot be beaten. The user gets immediate responses (or say promises), and a promise is always better than nothing. A blank screen scares people. Developers shouldn't be lazy to enhance perceived performance.

And finally some words about the dirty side. What you should do in order to get it work cross-browser.

  1. learn to think asynchronously
  2. organize your code to be modular
  3. organize your code to handle errors, edge cases well
  4. enhance progressively
  5. always take care of the right amount of feedback
galambalazs
Also check out LABjs which deals with this stuff for you. http://labjs.com/
Pointy
I myself am experimenting with such a project http://galambalazs.freeiz.com/multiload/
galambalazs
Thanks, galam. I guess I should have been more clear. I did expect this to be asynchronous in the end. I just want a way to access it that made logical sense to the programmer. I wanted to avoid things like:Import("package.mod1", function() { // do stuff with mod1});Import("package.mod2", function() { // do stuff with mod2});I took a look at your script and labjs and, while nice, seem to be more complex for my needs. I thought there may be a simpler way and wanted to avoid bringing in extra dependencies.
Josh Johnson
You missed the point of my post. It's all about the users. This should be your first priority. Everything else is secondary.
galambalazs
Galam, very good point. User experience is very important. To be clear, I'm not willing to sacrifice user experience OR quality, maintainable code. I'm going to look into closure and labjs to see what they can do for me. But for the time being I may need to stick with <script> tags. Unfortunately, I'm not working on this by myself. I work with a medium sized team of developers so maintainable code is high priority. If everyone can't figure out how to use the lib efficiently then user exp goes right out the window. Callbacks are intuitive. A callback because you imported a package are not.
Josh Johnson
Again, for clarity, "synchronous" was a bad choice of words used to get my point across. I don't want the browser to freeze as things are loading.
Josh Johnson
A: 

This isn't pretty, but it works:

<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"></script>');
</script>

<script type="text/javascript">
  functionFromOther();
</script>

Or

<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"></script>');
  window.onload = function() {
    functionFromOther();
  };
</script>

The script must be included either in a separate <script> tag or before window.onload().

This will not work:

<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"></script>');
  functionFromOther(); // Error
</script>

The same can be done with creating a node, as Pointy did, but only in FF. You have no guarantee when the script will be ready in other browsers.

Being an XML Purist I really hate this. But it does work predictably. You could easily wrap those ugly document.write()s so you don't have to look at them. You could even do tests and create a node and append it then fall back on document.write().

Josh Johnson