Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I keep everything in an external .js file. But not all functions are used on every page. Does this affect speed?

My app's JavaScript/jQuery is contained in an external scripts.js file. It generally looks like this:

$('document').on('ready', function() {
    giraffe();
    elephant();
    zebra();
});

function giraffe() {
    // code
}

function elephant() {
    // code
}

function zebra() {
    // code
}

giraffe() is only used for the view available at /animal/giraffe
elephant() is only used for the view available at /animal/elephant
zebra() is only used for the view available at /animal/zebra,

But all 3 are supposed to run on the view available /animal/all. This is a rudimentary example, but this is the reasoning behind having them all in one .js file, apart from keeping HTTP requests to a minimum.

My question is, does this affect the JavaScript rendering? Even though giraffe() isn't used (has no elements to work on) on /animal/zebra, it's still being called. Does js/jQuery ignore the function if it finds nothing to do? I'm sure the whole script is read, and that probably takes time. So, what's best way to handle this?

One solution

To avoid conflicts, I've created conditionals at the top of the js file to only run the functions that the active page needs:

$('document').on('ready', function() {
    var body = $('body');

    if( body.hasClass('giraffe') ) {
        giraffe();
    }

    if( body.hasClass('elephant') ) {
        elephant();
    }

    if( body.hasClass('zebra') ) {
        zebra();
    }
});

This is a little more verbose than I would like, but it is successful in keeping these functions modular/conflict free. I welcome an improvement on this solution.

like image 558
yosh-fo Avatar asked Jun 11 '13 10:06

yosh-fo


People also ask

What is better to load one complete JavaScript file on all pages or separate files based on different pages?

js can occupy the same file when you deploy your application. To better comprehension and developing, it is good to maintain them into separated files.

What is the advantage of using external js and CSS files?

The first major benefit of using external CSS style sheets and external JavaScript files is faster load times for your web pages. According to an experiment at Google, even a half a second difference in page load time can make a 20% difference in how much traffic that pages retain.

What are the benefits of using a separate JavaScript file rather than writing JavaScript code directly in HTML?

External JavaScript Advantages Placing scripts in external files has some advantages: It separates HTML and code. It makes HTML and JavaScript easier to read and maintain. Cached JavaScript files can speed up page loads.

How do I use an external JavaScript file?

To include an external JavaScript file, we can use the script tag with the attribute src . You've already used the src attribute when using images. The value for the src attribute should be the path to your JavaScript file. This script tag should be included between the <head> tags in your HTML document.


2 Answers

It would certainly be better to run just the code you need. It's not that difficult; the only minor complexity is handling your /animals/all case. If you want to keep all your code in one file, you could do it this way:

var animals = {
    giraffe: function() {
        console.log( "I'm a giraffe" );
    },
    elephant: function() {
        console.log( "I'm an elephant" );
    },
    zebra: function() {
        console.log( "I'm a zebra" );
    }
};

$(function() {
    var animal = location.pathname.split('/').pop();
    if( animal == 'all' ) {
        for( var animal in animals ) {
            animals[animal]();
        }
    }
    else if( animal in animals ) {
        animals[animal]();
    }
    else {
        console.log( "I'm a mystery animal" );
    }
});

You can actually test this code by going to URLs like this right here on Stack Overflow, and then pasting that code into the JavaScript console:

https://stackoverflow.com/animal/giraffe
https://stackoverflow.com/animal/elephant
https://stackoverflow.com/animal/zebra
https://stackoverflow.com/animal/ocelot
https://stackoverflow.com/animal/all

Update: OK, so you explained in the comment that the actual situation is a bit more complicated. I'll leave this code here in case it's useful for anyone, but for your situation you may be closer to what you need with the code you already have.

WRT the question of what one of your animal functions will do when you're on a page it doesn't relate to, of course that depends on how it's coded. It may successfully do nothing, or it may have an error, right?

Since we're talking about jQuery code, here are a couple of examples. Suppose you have code that's looking for an element by ID and then assumes that the element exists:

var zebraElement = $('#zebra')[0];
console.log( zebraElement.value );

On a page where the #zebra element exists, this code will log its value attribute. (I'm assuming for discussion that it's an element that has a value, such as an input element.)

But if #zebra is not present, then zebraElement is undefined, and attemping to access its value will fail and land in the debugger.

OTOH, if you coded that like this:

var $zebra = $('#zebra');
console.log( $zebra.val() );

it wouldn't fail if #zebra is missing, it would successfully print undefined without causing an error.

Similarly, if you have code that uses $().each(), it will typically run without failure when the element(s) are missing, because it simply won't execute the callback function:

$('.animal').each( function( i, e ) {
    console.log( $(e).val() );
});

If there are no elements with class="animal", then the console.log() call will never be reached. So there's no error, it just doesn't do anything.

Depending on what you're doing, this can be a perfectly reasonable way to fire up only the behavior you need—simply make sure your code handles the missing DOM elements by cleanly doing nothing.

Also be sure to read nick's answer for more insights.

And one more update… In the comment you mentioned keying off classnames on the body element. A nice way to do that would be similar to the code example above. You don't need a conditional for each animal, just a loop and a single conditional:

var animals = {
    giraffe: function() {
        console.log( "I'm a giraffe" );
    },
    elephant: function() {
        console.log( "I'm an elephant" );
    },
    zebra: function() {
        console.log( "I'm a zebra" );
    }
};

$(function() {
    var $body = $('body');
    for( var animal in animals ) {
        if( $body.hasClass(animal) ) {
            animals[animal]();
        }
    }
});

So, for example, if you have <body class="giraffe zebra"> it will call the animals.giraffe() and animals.zebra() functions.

like image 139
Michael Geary Avatar answered Nov 02 '22 05:11

Michael Geary


There are actually two issues here, one is whether to load all the functions and the other is whether to run them all. The question about whether to run them all (and some solutions to running just the functions you need) has been well addressed by Michael Geary in the other answers.

So, should you load them all? You need to weigh up the time needed to download a larger file over making extra http requests. With only three 'groups' of functions shared between 3 pages (and one page using all of them) and when you expect the user to be changing pages regularly I would go with one file.

Once your project gets very big you'll want to use something like requirejs to manage your scripts and load them asynchronously. Loading your js scripts asynchronously will increase the speed of the page (and the perceived speed of the page) and if there are issues (especially with scripts hosted by third-parties) your page wont get help up. You can of course do this without a library:

With HTML5:

<script async src="http://google.com/script.js"></script>

There are a million ways to load asynchronously with pure JS, one way:

<script>
  var resource = document.createElement('script'); 
  resource.src = "//google.com/script.js";
  var script = document.getElementsByTagName('script')[0];
  script.parentNode.insertBefore(resource, script);
</script>
like image 35
nick Avatar answered Nov 02 '22 06:11

nick