jQuery best practice - using selectors vs function(variable) - javascript

This is a general question about best practice in jQuery syntax/code organisation.
Consider the following snippet, used in a jQuery AJAX function:
if(obj.status == "error"){
$("#alert").html(obj.message);
}
I have also seen this written as:
function alert_box(str)
{
var html_str = '';
$("#alert").html(html_str);
}
if(obj.status == "error"){
alert_box(obj.message);
}
Functionally, this is precisely the same. My question: Is there any semantic or practical reason for differentiating between the two? What about load time / performance issues?

This is seems to be a question of "why use functions in general"? The idea behind a function is that you're making a code block reusable without having to write out the same code again. If you want to do that same thing in several places throughout your script, the function makes sense. If you only do that once, it may not be as practical. Then again, functions also help you hide details where you don't care about them - so you can summarize an action while the details of that action are somewhere in that function definition.
In this specific case, that function is broken anyway. Rather than using the passed in argument str, you have an empty variable html_str that you're replacing the html contents of an element with. Also, there's no need here to use html rather than text, which is better performance.
function alert_box(str) {
$("#alert").text(str);
}
Even though this is only a one liner, this can still be practical because it would let you use alert_box in several places throughout the script and not have to change those places later if you decide to change what alert_box does. Even something like changing the id of the element would require changes in several places, for example.
It also worth noting that this function searches the DOM for "#alert" each time it runs. It would be most optimal to cache that reference like this:
$alert = $("#alert");
function alert_box(str) {
$alert.text(str);
}
A few things that are great to study:
KISS
DRY
SOLID aka OOP

Related

JS Mini functions

Is it worth using mini functions in JavaScript? Example:
function setDisplay(id, status) {
document.getElementById(id).style.display = status;
}
And after that, each time you want to manipulate the display attribute of any given object, you could just call this function:
setDisplay("object1", "block");
setDisplay("object2", "none");
Would there be any benefit of coding this way?
It would reduce file size and consequently page load time if that particular attribute is changed multiple times. Or would calling that function each time put extra load on processing, which would make page loading even slower?
Is it worth using mini functions in JavaScript?
Yes. If done well, it will improve on:
Separation of concern. For instance, a set of such functions can create an abstraction layer for what concerns presentation (display). Code that has just a huge series of instructions combining detailed DOM manipulation with business logic is not best practice.
Coding it only once. Once you have a case where you can call such a function more than once, you have already gained. Code maintenance becomes easier when you don't have (a lot of) code repetition.
Readability. By giving such functions well chosen names, you make code more self-explaining.
Concerning your example:
function setDisplay(id, status) {
document.getElementById(id).style.display = status;
}
[...]
setDisplay("object1", "block");
setDisplay("object2", "none");
This example could be improved. It is a pity that the second argument is closely tied to implementation aspects. When it comes to "separation of concern" it would be better to replace that argument with a boolean, as essentially you are only interested in an on/off functionality. Secondly, the function should probably be fault-tolerant. So you could do:
function setDisplay(id, visible) {
let elem = document.getElementById(id);
if (elem) elem.style.display = visible ? "block" : "none";
}
setDisplay("object1", true);
setDisplay("object2", false);
Would there be any benefit of coding this way?
Absolutely.
would [it] reduce file size...
If you have multiple calls of the same function: yes. But this is not a metric that you should be much concerned with. If we specifically speak of "one-liner" functions, then the size gain will hardly ever be noticeable on modern day infrastructures.
...and consequently page load time
It will have no noticeable effect on page load time.
would calling that function each time put extra load on processing, which would make page loading even slower?
No, it wouldn't. The overhead of function calling is very small. Even if you have hundreds of such functions, you'll not see any downgraded performance.
Other considerations
When you define such functions, it is worth to put extra effort in making those functions robust, so they can deal gracefully with unusual arguments, and you can rely on them without ever having to come back to them.
Group them into modules, where each module deals with one layer of your application: presentation, control, business logic, persistence, ...
It would reduce file size and consequently page load time if that particular attribute is changed multiple times. Or would calling that function each time put extra load on processing, which would make page loading even slower?
It won't make the page's loading slower. Adding a few lines here and there with vanilla js won't effect the page loading time, after all, the page's loading time is the time to load the html js and css files, so a few lines in js won't effect it. A performance issue is unlikely to happen unless you're doing something really intended that brings you into a massive calculation or huge recursion.
Is it worth using mini functions in JavaScript?
In my opinion - Yes. You don't want to overuse that when unnecessary, after all, you don't want to write each line of code in a function right? In many cases, creating mini functions can improve the code's cleanness, readability and they can made it easier and faster to code.
With es6 you can use a single line functions with is very nice and easy:
const setDisplay = (id, status) => document.getElementById(id).style.display = status;
It doesn't really affect the performance unless you execute that function 10,000 or more times.
Jquery use mini functions, like $('#id').hide(); $('#id').show(); and $("#id").css("display", "none"); $("#id").css("display", "block");
It creates more readable code but it doesn't do that much to the performance.
var divs = document.querySelectorAll("div");
function display(div, state) {
div.style.display = state;
}
console.time("style");
for(var i = 0; i < divs.length; i++) {
divs[i].style.display = "none";
}
console.timeEnd("style");
console.time("function");
for(var j = 0; j < divs.length; j++) {
display(divs[j], "block");
}
console.timeEnd("function");
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
In terms of runtime performance I’d say it doesn’t make any difference. The JavaScript engines are incredibly optimized and are able to recognize that this function is being called often and to replace it by native code, and maybe even able to inline the function call so that the cost of calling an extra function is eliminated completely.
If your intent is to reduce the JavaScript files: you save a few tens of bytes for each place in the code where the function can be used, but even if you call this mini function 100 times, you will be saving 1 or 2 kb of uncompressed JavaScript. If you compare the final gzipped JavaScript (which should be how you serve your resources if you care about performance) I doubt there will be any noticeable difference.
You also need to think about how this type of code will be understood by your colleagues, or whoever may have to read this code in the future. How likely it is that a new programmer in your team knows the standard DOM API? Your non-standard functions might confuse your future teammates, and require them to look into the function body to know what they do. If you have one function like this it probably doesn’t make much of a difference, but as you start adding more and more mini functions for each possible style attribute you end up with hundreds of functions that people need to get used to.
The real benefit is ability to update on several places. Let say that you realize that you want to use classes instead of using styles. Instead of having to change on all places, you can just change that one method.
This is even more apparent when you read from a common source. Perhaps you have an API that you call with a single method.
let user = getData('user');
...but instead doing a API call, you want to use localforage to store the user data and read from the disk instead.
let user = getData('user');
... but you realized that it takes about 70-200 ms to read from localforage, so instead you store everything in memory, but reading from localforage if it's not in memory, and doing an API call if it's not in localforage. Getting user information is still the same:
let user = getData('user');
Just imagine if you wrote the whole call in every single place.
I usually create mini functions like these if I 1) read/write data, 2) if the code gets shorter OR more readable (i.e. the method name replaces comments), 3) or if I have repeatable code that I can sum up in a dynamic way.
Also, to quote from the book Clean Code: each function should do only one thing. Thinking in terms of mini functions helps with that.
I'm not fully sure of what a mini function is but if you're asking whether it's better to define functions for code that needs to be called multiple times instead of typing out/ copy-pasting those same lines of code over and over then it's better to go with option 1 for readability and file-size.
It would reduce file size and consequently page load time if that particular attribute is changed multiple times. Or would calling that function each time put extra load on processing, which would make page loading even slower?
It's not in typical scenarios possible for the usage of such functions to put (any significant) extra load on processing that would slow down the document parsing, it's likeliness to do that would however depend on when and how you call your code to be executed but it's not like you'll be looping O(N3) and calling such functions thousands of times to impact page loading (right?) - if anything, predefined functions like that meant to take dynamic inputs would make your code neater, more uniform looking and reduce file-size... with a very tiny obvious overhead when compared to directly accessing properties without having to go through another function. So you decide whether you want to take up that bargain depending on whether the frequency of you calling functions like that would be significant enough to be considered.
I'm sure most engines optimize repetitive code so it's (or nearly) equivalent to the same thing anyway so I'd choose readability and improve how easy it is for others to understand and follow through code instead.
JavaScript is prototype language on top of that going on a leaf to say everything in JavaScript is an object so its object oriented as object oriented gets to be although at a very different level.
So the question is like we create classes in object oriented, would we develop script framework as functional programming or prototype and what will be performance hit.
so lets consider this very fine example.
function abc(name, age) {
this.name = name;
this.age = age;
}
person1 = new abc('jhon', 25);
person2 = new abc('mark', 46);
console.log(person1.age);console.log(person2.age);
person1.father = 'mark';
console.log(person1.father);
we have created a function and have used the power of this in the scope of function thus every new insurance will carry this information. and no two instances will be alike.
Then down the a line we have used prototype to add father information on instance. This where prototyping becomes awesome. Thus whole this scoping + instance + prototyping is fast.
function abc(name, age) {
name = name;
age = age;
return name; // its either name or age no two values
}
person1 = abc('jhon', 25);
person2 = abc('mark', 46);
console.log(person1);
console.log(person2);
abc.father = 'mark';
console.log(person1.father);
console.log(abc.father);
we tried the same on functional sense the whole thing fell apart. no instance + no this scoping + no new prototyping delegating down the line. Thus in long run this approach will reduce performance as one would have to re-fetch things over and over again on top of that with t=out this scoping we are only returning single factor where as with this scooping we are packing a lot more into object. this one point.
function abc(name, age) {
this.name = name;
this.age = age;
}
person1 = new abc('jhon', 25);
person1.fatherName = 'Mark';
person1.fatherUpdate = function (d){this.fatherAge = this.fatherName+' '+d;};
person1.fatherUpdate(56);
console.log(person1.fatherAge);
Now have added more complexity we have carried this down the line hence the scope and have added functions on top of it.
This will literally make your hair fall out if things were done in pure functional way.
Always keep in mind any given function can and may compute and execute as many things you want but it will always give single return with 99% of the time single property.
If you need more prototype way with scoping as above.
jquery way of doing things.
I had made my framework ActiveQ which uses the above its almost 30 Kb unminified and does everything jquery does and much more with template engine.
anyways lets build example - it is an example so please be kind ;
function $(a){
var x;
if(x = document.querySelector(a)) return x;
return;}
console.log($('div'));
console.log($('p'));
<div>abc</div>
Now this almost 50% of your jquery selector library in just few lines.
now lets extended this
function $(a){
this.x = document.querySelector(a);
}
$.prototype.changeText = function (a){
this.x.innerHTML = a;
}
$.prototype.changeColor = function (a){
this.x.style.color = a;
}
console.log(document.querySelector('div').innerText);
app = new $('div');
app.changeText('hello');
console.log(document.querySelector('div').innerText);
app.changeColor('red');
<div>lets see</div>
what was the point of the whole above exercise you wont have to search through DOM over and over again as long as long one remains in scope of the function with this
Obviously with pure functional programming one would have to search though all over again and again.
even jquery at time forgets about what it had searched and one would have to research because this context is forwarded.
lets do some jquery style chaining full mode way - please be kind its jusrt an example.
function $(a){
return document.querySelector(a);
}
Element.prototype.changeText = function (a){
this.innerHTML = a;
return this;
}
Element.prototype.changeColor = function (a){
this.style.color = a;
return this;
}
console.log($('div').innerText);
//now we have full DOm acces on simple function reurning single context
//lets chain it
console.log($('div').changeText('hello').changeColor('red').innerText);
<div>lets see</div>
See the difference less line of code is way faster in performance as its working with the browser rather then pure functional way rather then creating a functional call load and search load all repeatedly
so you need to perform bunch of tasks with single output stick to functions as in conventional way and if you need to perform bunch of tasks on context as in last example where context is to manipulate properties of the element as compared to $ function which only searches and returns the element.

Should I be caching jQuery selectors in the global namespace? [duplicate]

I have some trouble that comes from my Javascript (JS) codes, since I sometimes need to access the same DOM elements more than once in the same function. Some reasoning is also provided here.
From the point of view of the performance, is it better to create a jQuery object once and then cache it or is it better to create the same jQuery object at will?
Example:
function(){
$('selector XXX').doSomething(); //first call
$('selector XXX').doSomething(); //second call
...
$('selector XXX').doSomething(); // n-th call
}
or
function(){
var obj = $('selector XXX');
obj.doSomething(); //first call
obj.doSomething(); //second call
...
obj.doSomething(); // n-th call
}
I suppose that the answer probably depends by the value of "n", so assume that n is a "small" number (e.g. 3), then a medium number (e.g. 10) and finally a large one (e.g. 30, like if the object is used for comparison in a for cycle).
Thanks in advance.
It is always better to cache the element, if n is greater than 1, cache the element, or chain the operations together (you can do $('#something').something().somethingelse(); for most jQuery operations, since they usually return the wrapped set itself). As an aside, it has become a bit of a standard to name cache variables beginning with a money sign $ so that later in the code it is evident that you are performing an operation on a jQuery set. So you will see a lot of people do var $content = $('#content'); then $content.find('...'); later on.
The second is superior. Most importantly, it is cleaner. In the future, if you want to change your selector, you only need to change it one place. Else you need to change it in N places.
Secondly, it should perform better, although a user would only notice for particularly heavy dom, or if you were invoking that function a lot.
If you look at this question from a different perspective, the correct answer is obvious.
In the first case, you're duplicating the selection logic in every place it appears. If you change the name of the element, you have to change each occurence. This should be reason enough to not do it. Now you have two options - either you cache the element's selector or the element itself. Using the element as an object makes more sense than using the name.
Performance-wise, I think the effect is negligible. Probably you'll be able to find test results for this particular use-case: caching jQuery objects vs always re-selecting them. Performance might become an issue if you have a large DOM and do a lot of lookups, but you need to see for yourself if that's the case.
If you want to see exactly how much memory your objects are taking up, you can use the Chrome Heap Profiler and check there. I don't know if similar tools are available for other browsers and probably the implementations will vary wildly in performance, especially in IE's case, but it may satisfy your curiosity.
IMO, you should use the second variant, storing the result of the selection in an object, no so much as to improve performance but to have as little duplicate logic as possible.
As for caching $(this), I agree with Nick Craver's answer. As he said there, you should also use chaining where possible - cleans up your code and solves your problem.
You should take a look at
http://www.artzstudio.com/2009/04/jquery-performance-rules/
or
http://addyosmani.com/jqprovenperformance/
I almost always prefer to cache the jQuery object but the benefit varies greatly based on exactly what you are using for your selector. If you are using ids then the benefit is far less than if you are using types of selectors. Also, not all selectors are created equally so try to keep that in mind when you write your selectors.
For example:
$('table tr td') is a very poor selector. Try to use context or .find() and it will make a BIG difference.
One thing I like to do is place timers in my code to see just how efficient it is.
var timer = new Date();
// code here
console.log('time to complete: ' + (new Date() - timer));
Most cached objects will be performed in less than 2 milliseconds where as brand new selectors take quite a bit longer because you first have to find the element, and then perform the operation.
In JavaScript, functions are generally short-lived—especially when hosted by a browser. However, a function’s scope might outlive the function. This happens, for example, when you create a closure. If you want to prevent a jQuery object from being referenced for a long time, you can assign null to any variables that reference it when you are done with that variable or use indirection to create your closures. For example:
var createHandler = function (someClosedOverValue) {
return function () {
doSomethingWith(someClosedOverValue);
};
}
var blah = function () {
var myObject = jQuery('blah');
// We want to enable the closure to access 'red' but not keep
// myObject alive, so use a special createHandler for it:
var myClosureWithoutAccessToMyObject = createHandler('red');
doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject);
// After this function returns, and assuming doSomethingElseWith() does
// not itself generate additional references to myObject, myObject
// will no longer have any references and be elligible for garbage
// collection.
}
Because jQuery(selector) might end up having to run expensive algorithms or even walk the DOM tree a bit for complex expressions that can’t be handled by the browser directly, it is better to cache the returned object. Also, as others have mentioned, for code clarity, it is better to cache the returned object to avoid typing the selector multiple times. I.e., DRY code is often easier to maintain than WET code.
However, each jQuery object has some amount of overhead. So storing large arrays of jQuery objects in global variables is probably wasteful—unless if you actually need to operate on large numbers of these objects and still treat them as distinct. In such a situation, you might save memory by caching arrays of the DOM elements directly and using the jQuery(DOMElement) constructor which should basically be free when iterating over them.
Though, as people say, you can only know the best approach for your particular case by benchmarking different approaches. It is hard to predict reality even when theory seems sound ;-).

Caching of javascript variables [duplicate]

I have some trouble that comes from my Javascript (JS) codes, since I sometimes need to access the same DOM elements more than once in the same function. Some reasoning is also provided here.
From the point of view of the performance, is it better to create a jQuery object once and then cache it or is it better to create the same jQuery object at will?
Example:
function(){
$('selector XXX').doSomething(); //first call
$('selector XXX').doSomething(); //second call
...
$('selector XXX').doSomething(); // n-th call
}
or
function(){
var obj = $('selector XXX');
obj.doSomething(); //first call
obj.doSomething(); //second call
...
obj.doSomething(); // n-th call
}
I suppose that the answer probably depends by the value of "n", so assume that n is a "small" number (e.g. 3), then a medium number (e.g. 10) and finally a large one (e.g. 30, like if the object is used for comparison in a for cycle).
Thanks in advance.
It is always better to cache the element, if n is greater than 1, cache the element, or chain the operations together (you can do $('#something').something().somethingelse(); for most jQuery operations, since they usually return the wrapped set itself). As an aside, it has become a bit of a standard to name cache variables beginning with a money sign $ so that later in the code it is evident that you are performing an operation on a jQuery set. So you will see a lot of people do var $content = $('#content'); then $content.find('...'); later on.
The second is superior. Most importantly, it is cleaner. In the future, if you want to change your selector, you only need to change it one place. Else you need to change it in N places.
Secondly, it should perform better, although a user would only notice for particularly heavy dom, or if you were invoking that function a lot.
If you look at this question from a different perspective, the correct answer is obvious.
In the first case, you're duplicating the selection logic in every place it appears. If you change the name of the element, you have to change each occurence. This should be reason enough to not do it. Now you have two options - either you cache the element's selector or the element itself. Using the element as an object makes more sense than using the name.
Performance-wise, I think the effect is negligible. Probably you'll be able to find test results for this particular use-case: caching jQuery objects vs always re-selecting them. Performance might become an issue if you have a large DOM and do a lot of lookups, but you need to see for yourself if that's the case.
If you want to see exactly how much memory your objects are taking up, you can use the Chrome Heap Profiler and check there. I don't know if similar tools are available for other browsers and probably the implementations will vary wildly in performance, especially in IE's case, but it may satisfy your curiosity.
IMO, you should use the second variant, storing the result of the selection in an object, no so much as to improve performance but to have as little duplicate logic as possible.
As for caching $(this), I agree with Nick Craver's answer. As he said there, you should also use chaining where possible - cleans up your code and solves your problem.
You should take a look at
http://www.artzstudio.com/2009/04/jquery-performance-rules/
or
http://addyosmani.com/jqprovenperformance/
I almost always prefer to cache the jQuery object but the benefit varies greatly based on exactly what you are using for your selector. If you are using ids then the benefit is far less than if you are using types of selectors. Also, not all selectors are created equally so try to keep that in mind when you write your selectors.
For example:
$('table tr td') is a very poor selector. Try to use context or .find() and it will make a BIG difference.
One thing I like to do is place timers in my code to see just how efficient it is.
var timer = new Date();
// code here
console.log('time to complete: ' + (new Date() - timer));
Most cached objects will be performed in less than 2 milliseconds where as brand new selectors take quite a bit longer because you first have to find the element, and then perform the operation.
In JavaScript, functions are generally short-lived—especially when hosted by a browser. However, a function’s scope might outlive the function. This happens, for example, when you create a closure. If you want to prevent a jQuery object from being referenced for a long time, you can assign null to any variables that reference it when you are done with that variable or use indirection to create your closures. For example:
var createHandler = function (someClosedOverValue) {
return function () {
doSomethingWith(someClosedOverValue);
};
}
var blah = function () {
var myObject = jQuery('blah');
// We want to enable the closure to access 'red' but not keep
// myObject alive, so use a special createHandler for it:
var myClosureWithoutAccessToMyObject = createHandler('red');
doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject);
// After this function returns, and assuming doSomethingElseWith() does
// not itself generate additional references to myObject, myObject
// will no longer have any references and be elligible for garbage
// collection.
}
Because jQuery(selector) might end up having to run expensive algorithms or even walk the DOM tree a bit for complex expressions that can’t be handled by the browser directly, it is better to cache the returned object. Also, as others have mentioned, for code clarity, it is better to cache the returned object to avoid typing the selector multiple times. I.e., DRY code is often easier to maintain than WET code.
However, each jQuery object has some amount of overhead. So storing large arrays of jQuery objects in global variables is probably wasteful—unless if you actually need to operate on large numbers of these objects and still treat them as distinct. In such a situation, you might save memory by caching arrays of the DOM elements directly and using the jQuery(DOMElement) constructor which should basically be free when iterating over them.
Though, as people say, you can only know the best approach for your particular case by benchmarking different approaches. It is hard to predict reality even when theory seems sound ;-).

How much overhead is there when traversing the DOM?

(I'm using prototype.js here, but I imagine the same holds true across other libraries as well)
I often find myself writing code like this:
var search_box;
Event.observe(window, 'load', function() {
search_box = $('search_box');
});
function doSomething(msg) {
search_box.innerHTML = msg;
}
Rather then writing it simply like this:
function doSomething(msg) {
$('search_box').innerHTML = msg;
}
My intention is to avoid having to traverse the entire DOM searching for the "search_box" element everything I need access to it. So I search for it once on page load and then stick the reference in a global variable. However, I don't recall ever seeing anyone else do this? Am I needlessly making my code more complex?
This is called premature optimization.
You are introducing a global variable to optimize something you have not profiled.
Your assumption that the $ "traverses the DOM" is incorrect. This function is implemented using document.getElementById which is the fastest way to access an element in the DOM.
I suggest coding your javascript using basic programming best practices such as avoiding global variables, and not optimizing without profiling. Once your application is working as expected, then you should profile it (using firebug) and address the area(s) where it is slow.
I usually do the same thing, the reason you don't see it often is probably because you don't see well written code often that's optimized ( nevermind the whole preoptimization is evil thing ) - I say if you can optimize it without headaches then why not?
Realistically speaking though that's a very very trivial DOM lookup, you should only begin to worry if you're iterating through dozens of elements and being vague in the selectors.. so I wouldn't worry too much about it unless you can really notice certain parts of your web page loading rather slowly, in which case you should store the multiple elements you access in the outer scope's variable.
Good:
(function() {
var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.
function foo() {
els.something();
}
els.somethingElse();
})();
Bad:
(function() {
var els = $$('.foo span'); // also better to specify a context but I'm not sure how that's done in Prototype, it's the second param in jQuery.
function foo() {
$$('.foo span').something();
}
$$('.foo span').somethingElse();
})();
I decided to spend a bit of time doing some testing to get some hard data. The answer is that preloading the elements into global variables is twice as efficient as accessing them using the DOM getElementById method. (At least under FF 3.6).
Subsequent accesses to the objects is also more efficient using the global variable method, but only marginally so.

Why is dynamically modifying a JavaScript function's code mid-execution a bad thing?

A few days ago, I asked a question regarding dynamically modifying a function's code midway through the outerlying script's execution and I was told to completely forget ever coming upon the notion. I'm not sure I understand why that is. Let me give an example:
<script>
var display = function(msg)
{
alert(msg);
}
// Now, at the moment, the display() function
// is receiving a single parameter and alerting
// it to the user. I'm now going to use eval()
// to modify the display() function.
eval('display = ' + display.toString().replace('alert(', 'document.write('));
// Now, the display() function writes its parameter
// to the document as opposed to alerting it.
</script>
I realize this is a rather trivial example, but there must surely be some use that can be derived from being able to dynamically modify a function, something so useful by itself.
Although this may do what you need it to do, 6 months from now you (or the person maintaining your code) will be going "WTF?!"
If your use case is to alert or write based on some condition, why don't you write two different functions? Or have your function take another parameter that decides the output mode. Or pass in a function as a parameter that performs the actual output. Something, you know, a little more on the sane side. ;-)
There are cases where it could be useful to change a function's behavior, but there are better ways to do it. In your example, you could create new instances of the function that handle the output differently, by passing a function as an argument (similar to the strategy pattern):
function makeDisplay(displayStrategy) {
return function(msg) {
// I'm assuming you would do some additional processing here...
displayStrategy(msg);
}
}
var display = makeDisplay(alert);
// now modify display to use document.write
display = makeDisplay(function(msg) { document.write(msg); });
Well, using eval might be a security concern but modifying a function in real-time is ok. How else you can make memoization anyway?
Although, come to think of it, changing method signature isn't a great idea, other people won't know how to call this function after this, since it would depend on execution order and it's not easy to track usually.
I have found myself needing to do this in situations where I don't have the source code for a particular piece of vendor javascript; so that could be a legitimate use case. I agree that if you have another option, it's better to do it in a more organised way, editing the original function to be more flexible.

Categories