Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery code organization and performance

After doing some research on the subject, I've been experimenting a lot with patterns to organize my jQuery code (Rebecca Murphy did a presentation on this at the jQuery Conference for example).

Yesterday I checked the (revealing) module pattern. The outcome looks a bit reminiscent of the YUI syntax I think:

//global namespace MyNameSpace
if(typeof MNS=="undefined"||!MNS){var MNS={};}

//obfuscate module, just serving as a very simple example
MNS.obfuscate = function(){
    //function to create an email address from obfuscated '@'
    var email = function(){
        $('span.email').each(function(){
            var emailAddress = $(this).html().replace(' [ @ ] ','@');
            $(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');

        });
    };    
    return {
        email: email
    };    
}();

//using the module when the dom's ready
jQuery(document).ready(function($){
    MNS.obfuscate.email();
});

In the end I had several modules. Some naturally included "private members", which in this case means variables and/or functions which were only of importance for other functions within this module, and thus didn't end up in the return statement.

I thought having connected parts of my code (everything which has to do with the search for example) combined in a module makes sense, gives the whole thing structure.

But after writing this, I read an article by John (Resig), where he also writes about the performance of the module pattern:

"Instantiating a function with a bunch of prototype properties is very, very, fast. It completely blows the Module pattern, and similar, out of the water. Thus, if you have a frequently-accessed function (returning an object) that you want people to interact with, then it's to your advantage to have the object properties be in the prototype chain and instantiate it. Here it is, in code:

// Very fast
function User(){}
    User.prototype = { /* Lots of properties ... */ };

// Very slow
function User(){
    return { /* Lots of properties */ };
}

(John mentions he is not against the module pattern "per se" though - just to let you know :)

Then I wasn't sure anymore if I was going into the right direction with my code. The thing is: I don't really need any private members, and I also don't think I need inheritance for the time being. All I want for now is a readable/maintainable pattern. I guess this boils down to personal preference to a certain extend, but I don't wanna end up with readable code which has (rather serious) performance issues.

I'm no JavaScript expert and thus even less of an expert when it comes to performance testing. So first, I don't really know in how far the things John mentioned ("frequently-accessed function (returning an object) that you want people to interact with", lots of properties, etc.) apply to my code. The documents my code interacts with are not huge, with 100s or 1000s of elements. So maybe it's not an issue at all.

But one thing which came to my mind is that instead of just having

$('span.email').each(function(){
    var emailAddress = $(this).html().replace(' [ @ ] ','@');
    $(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});

(inside the domready function), I create two "extra" functions, obfuscate and email, due to the use of the module pattern. The creation of additional functions costs some time. The question is: will it be measurable in my case?

I'm not sure if a closure is created in my example above (in an interesting post on the jQuery forum I read the following: "There is a philosophical debate on whether an inner function creates a closure if it doesn't reference anything on an outer function's variable object..."), but I did have closures in my real code. And even though I don't think I had any circular references in there, I don't know in how far this could lead to high(er) memory consumption/problems with garbage collection.

I'd really like to hear your input on this, and maybe see some examples of your code. Also, which tools do you prefer to get information on execution time, memory and CPU usage?

like image 690
north Avatar asked Mar 04 '10 08:03

north


People also ask

Does jQuery affect performance?

However, there is a real negative performance impact from using jQuery, which is especially relevant when using it for the frontend of a website where it can harm end user experience.

Is jQuery modular?

jQuery was separated into modules to encourage usage of these subcomponents. If you're extremely concerned about bytes, and you only need a part of jQuery, only declare dependencies on the pieces you need.

How does jQuery function work?

At its core, jQuery is used to connect with HTML elements in the browser via the DOM. The Document Object Model (DOM) is the method by which JavaScript (and jQuery) interact with the HTML in a browser. To view exactly what the DOM is, in your web browser, right click on the current web page select “Inspect”.


1 Answers

I also don't think I need inheritance for the time being

Indeed. This doesn't really apply to using modules as a namespace. It's about class instance analogues.

Objects you create by making every instance from a completely new {name: member} object are less efficient than objects you create using new Class with Class.prototype.name= member. In the prototype case the member value is shared, resulting in lighter-weight instances.

In your example MNS is a singleton, so there is no benefit to be had by sharing members through a prototype.

I'm not sure if a closure is created in my example above

Yes, it is. Even when no variables are defined in the outer function, there is still a LexicalEnvironment and scope object created for the outer function, with this and arguments bound in it. A clever JS engine might be able to optimise it away, since every inner function must hide this and arguments with their own copies, but I'm not sure that any of the current JS implementations actually do that.

The performance difference, in any case, should be undetectable, since you aren't putting anything significant in the arguments. For a simple module pattern I don't think there's any harm.

Also, which tools do you prefer to get information on execution time, memory and CPU usage?

The place to start is simply to execute the code 10000 times in a for-loop and see how much bigger new Date().getTime() has got, executed several times on as many different browsers as you can get hold of.

$(this).html().replace(' [ @ ] ','@');

(What is this supposed to do? At the moment it will read the HTML of the span into a new String, replace only the first instance of [ @ ] with @, and return a new String value. It won't change the existing content in the DOM.)

like image 65
bobince Avatar answered Oct 27 '22 17:10

bobince