views:

357

answers:

7

I am not a huge JavaScript performance guru. Simply wondering, can I make the following code anymore compact? Not as in packing or compressing it, but in the way it's written.

(function() {
    var jq = document.createElement('script');
    var an = document.createElement('script');
    var cm = document.createElement('script');
    var ga = document.createElement('script');
    var domain = 'http://example.com/';

    jq.src = domain + 'jquery.1.3.2.js';
    an.src = domain + 'jquery.alphanumeric.js';
    cm.src = domain + 'common.js';
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    ga.setAttribute('async', 'true');

    document.documentElement.firstChild.appendChild(jq);
    document.documentElement.firstChild.appendChild(cm);
    document.documentElement.firstChild.appendChild(an);
    document.documentElement.firstChild.appendChild(ga);
})();

Cheers guys!

+1  A: 
'https:' == document.location.protocol ? 'https://ssl' : 'http://www'

can become:

'http' + 'https:'==document.location.protocol ? 's://ssl' : '://www'

That's the only improvement I can see, unless you're willing to go for non standard javascript, rather than creating elements, but the actual html elements into a string, then append it to the documents .innerHTML

Jeffrey Aylesworth
Interesting. I was simply wondering if there was a way of combining the var's or all the dom instructions. I guess not then :)
James
+7  A: 

Compactness in the way it's written, and performance, are unrelated. But to write it in a more compact, re-usable way:

function appendScript(url, async) {
  var el = document.createElement('script');
  el.src = url;
  if (async) el.setAttribute('async', 'true');
  document.documentElement.firstChild.appendChild(el);
}

(function() {
  appendScript('http://example.com/js/jquery.1.3.2.js',false);
  appendScript('http://example.com/js/jquery.alphanumeric.js', false);
  appendScript('http://example.com/js/common.js', false);
  appendScript(('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'), true);
})();
gWiz
+1 but being picky it might be worth using a variable for the domain
Pool
Definitely you will want to have the domain be a variable -- this refactor adds inflexibility.
artlung
Definitely? As The Feast said, it "might" be worth it. In my opinion, this is a simple problem met with a simple solution. Making the domain a variable adds complexity (albeit small) and reduces performance for practically no benefit (save a few bytes of bandwidth?).
gWiz
I'll back off "definitely" -- fine, but if you need to use it on a development server or on a local server it needs a rewrite. Sure, you can search and replace, but having it as a variable makes it easy for other developers to modify.
artlung
Good point, tho if that is the concern the script URLs could simply be relative.
gWiz
+1  A: 
var child1 = document.documentElement.firstChild;
child1.appendChild(jq);
child1.appendChild(cm);
child1.appendChild(an);
child1.appendChild(ga);
o.k.w
A: 

You could create an addScriptElement() function to make this way less repetitive.

Moishe
A: 

I'm sure this will get downvoted for 'bloat', but just sharing how I would do it:

First, I will define such a function that will be highly extensible:

function addElements(objlist) {
    // One or many
    objlist = [].concat(objlist);

    while(objlist.length > 0) {
        var current = objlist.pop();

        var node = document.createElement(current.element || 'div');
        for(attr in current.attributes)
            node.setAttribute(attr, current.attributes[attr]);

        if(current.parent)
            current.parent.appandChild(node);
    }
}

Then, to use it:

addElements([
    {
        parent: document.documentElement.firstChild,
        element: 'script',
        attributes: {
            src: 'http://example.com/jquery.1.3.2.js'
        }
    },
    {
        parent: document.documentElement.firstChild,
        element: 'script',
        attributes: {
            src: 'http://example.com/jquery.alphanumeric.js'
        }
    },
    {
        parent: document.documentElement.firstChild, 
        element: 'script',
        attributes: {
            src: 'http://example.com/common.js'
        }
    },
    {
        parent: document.documentElement.firstChild, 
        element: 'script',
        attributes: {
            src: ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js',
            async: true
        }
    }
]);

That's what I call 'power functions'. It's highly readable, and even though there's repetition, it's expressed with power.

You could even automate the object creation:

var elements = [
    'jquery.1.3.2.js',
    'jquery.alphanumeric.js',
    'common.js',
    ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'
];

for(var i=0; i<4; ++i) {
    elements[i] = {
        element: 'script',
        parent: document.documentElement.firstChild,
        attributes: {
            src: 'http://example.com/' + elements[i]
        }
    };
}

elements[3].attributes.async = true;

addElements(elements);
LiraNuna
I'm not gonna downvote, but why go to so much trouble for something that can be done in just a few lines?
Moishe
For the sake of 'power'. I love generalizing and writing functions that will do 'everything'. It may seem a bad example in this specific case, but it made me want to write and share such a method.
LiraNuna
Good to share though. With your disclaimer in your 1st line, you won't get any down-vote. Certainly not from me :P
o.k.w
A: 

Ok, here is my shot at this. Not sure it saves so much right now, but if you ended up with more assets on example.com it would speed things up.

(function(){
    var scripts    = ['jquery.1.3.2', 'jquery.alphanumeric', 'common'],
        head       = document.documentElement.firstChild,
        domain     = 'http://example.com/',
        add_script = function(url, async){
            var script = document.createElement('script');
            script.src = url;
            if(async === true) script.setAttribute('async', 'true');
            head.appendChild(script);
        };

    for(script in scripts) add_script( domain + scripts[script] + '.js' );

    add_script( ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js', true);
})();
Doug Neiner
A: 

Here's one approach. Hopefully this makes it straightforward to add or remove scripts (which do or do not need the async attribute:

({
    DOMAIN : 'http://example.com/',
    SCRIPTS : [ {file:'jquery.1.3.2.js'},
            {file:'jquery.alphanumeric.js'},
            {file:'common.js'},
            {file: ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'
                , async: 'true'} ],
    init: function() {
        for (var i in this.SCRIPTS) {
            var script = this.SCRIPTS[i];
            var sc = document.createElement('script');
            sc.src = (script.file.match(/^http/gi)) ? sc.src = script.file : sc.src = this.DOMAIN + script.file;
            if (typeof script.async !== 'undefined') {
                sc.setAttribute('async', script.async);
            }
            document.documentElement.firstChild.appendChild(sc);
        }

    }
}).init();
artlung