views:

80

answers:

2

When does JavaScript evaluate a function? Is it on page load or when the function is called?

The reason why I ask is because I have the following code:

function scriptLoaded() {
   // one of our scripts finished loading, detect which scripts are available:
   var jQuery = window.jQuery;
   var maps = window.google && google.maps;

   if (maps && !requiresGmaps.called) {
     requiresGmaps.called = true;
     requiresGmaps();
   }
   if (jQuery && !requiresJQuery.called) {
     requiresJQuery.called = true;
     requiresJQuery();
   }
   if (maps && jQuery && !requiresBothJQueryGmaps.called) {
     requiresBothJQueryGmaps.called = true;
     requiresBothJQueryGmaps();
   }
}
// asynch download of script
function addScript(url) {
    var script = document.createElement('script');
    script.src = url;
    // older IE...
    script.onreadystatechange=function () {
      if (this.readyState == 'complete') scriptLoaded.call(this);
    }
    script.onload=scriptLoaded;

    document.getElementsByTagName('head')[0].appendChild(script);
}

addScript('http://google.com/gmaps.js');
addScript('http://jquery.com/jquery.js');

// define some function dependecies
function requiresJQuery() { // create JQuery objects }
function requiresGmaps() { // create Google Maps object, etc }
function requiresBothJQueryGmaps() { ... }

What I want to do is perform asynchronous download of my JavaScript and start at the earliest possible time to begin executing those scripts but my code has dependencies on when the scripted have been obviously downloaded and loaded.

When I try the code above, it appears that my browser is still attempting to evaluate code within my require* functions even before those functions have been called. Is this correct? Or am I misunderstanding what's wrong with my code?

+5  A: 

Functions are evaluated when called.

For example

function test() {
    window.foo = 'bar';
}

console.log(window.foo); // => undefined
test();
console.log(window.foo); // => bar

Even though test was created before the first console.log, window.foo is not populated until test is actually called.

If your requires* functions are hanging/blocking, then you need to show the code for those (why would you not provide the source for the problematic ones?)

Edit:

Currently, your site is blanking out on me when you attach the loaded <script> to the <head>.

Anyway, a quick fix would be to place the scripts you wants near the bottom of the page, before </body>, because only scripts in <head> will fully block the page while loading.

There are some elegant ways to late-load resources, but, to keep it simple ..

<script type="text/javascript" src="http://path/to/jquery.js"&gt;&lt;/script&gt;
<script type="text/javascript">
requiresJQuery(); // jQuery is available at this point
</script>
</body>

The point is that, since the <script> is placed AFTER your main elements, the DOM elements will be available (and potentially loaded) before the browser starts to download your other libraries.

Matt
@Matt, I linked to the live site in the original post now. See update.
Benj
@Matt, also - I'm basically looking for ways to make my web site load faster and a big one I've noticed is that JS is blocking. You can see my live site at /. What I'm trying do to with the linked html page is rework my frontpage to remove the inherit JS blocking to perform earlier JS processing if possible (if that makes sense)
Benj
@Benj see my update
Matt
@Matt, see my previous comment. I don't want blocking and I want to download my JS asynchronously. Isn't what you just described in your EDIT is to have JS block and not download asynch?
Benj
@Benj - the strategy in my answer is only "perceived" async. It actually DOES block, but only after the DOM has loaded (because the `<script>` is right before `</body>`). For "true" async, you'll want to look at something like [LazyLoad](http://wonko.com/post/painless_javascript_lazy_loading_with_lazyload)
Matt
@Matt, I don't think I'm explaining my question very well. I can't lazy load because I absolutely *need* those JQuery present to display my web site. Web site is being dynamically rendered. 1) The major of the web page is a Google Map map, so I don't want to lazy load that since it's a huge visual component to the site. I then use JQuery to render the other 1/3 of my page which is which homes to display on the Google map. As such, I don't want to lazy load - I simply want to perform true asynch download to load the Google Maps and JQuery libraries as fast as possible. Make sense?
Benj
@Benj - your requirements are not achievable, then. Browsers load JavaScript synchronously - period. Your only option around this is to render "as much as you can" + DIV placeholders, then populate those DIVs after LazyLoading various libraries.
Matt
A: 

Yes, you are probably misunderstanding. Even if your functions contain a syntax error, it should not matter until you actually call the function.

Could it be that you're calling those functions from somewhere else? Maybe you didn't provide accurate code samples?

Fyodor Soikin
@Fyodor Soikin, I linked to the live site in the original post now. See update.
Benj
I don't see a link to the original site. Did you remove it already?
Fyodor Soikin