document.createElement("script") synchronously

Josh Johnson picture Josh Johnson · Jul 14, 2010 · Viewed 241.9k times · Source

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."

Answer

Pointy picture Pointy · Jul 14, 2010

You can create your <script> element with an "onload" handler, and that will be called when the script has been loaded and evaluated by the browser.

var script = document.createElement('script');
script.onload = function() {
  alert("Script loaded and ready");
};
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);

You can't do it synchronously.

edit — it's been pointed out that, true to form, IE doesn't fire a "load" event on <script> tags being loaded/evaluated. Thus I suppose the next thing to do would be to fetch the script with an XMLHttpRequest and then eval() it yourself. (Or, I suppose, stuff the text into a <script> tag you add; the execution environment of eval() is affected by the local scope, so it won't necessarily do what you want it to do.)

editAs of early 2013, I'd strongly advise looking into a more robust script loading tool like Requirejs. There are a lot of special cases to worry about. For really simple situations, there's yepnope, which is now built into Modernizr.