I am trying to increase the jquery performance of my mobile html 5 app. I read some guides about storing used jquery selectors in global objects. The app is pretty big and I didn't expected a big perfomrance boost, but the app was running even slower (like 20%).
I only use jquery to find elements by Id ( $("#id") or $_element.find("#id")). Ids are unique, so I am only interested in finding the first element. I managed to globalize all jquery calls in a cacheHandler object, which stores all selectors by id. The cache is cleared frequently and contains around 30 elements per cycle.
With this changes the app ran slower, so I tried some more things to increase performance:
cache[id] = $(document.getElementById("id"))
cache[id] = document.getElementById("id")
store selectors with hashCode: cache[id.hashCode()]
I came up with the idea, that this solution is slow, because the memory is increased frequently, because the whole dom with all its children is stored in the cache.
So I had the new Idea, to cache the element path as array, like
document.body.children[1].children[5].children[0] => [1,5,0]
So I just have to find the element once, store the array and look up the path, if I need the element again.
This doesn't change anything, and all ideas were even slower than calling $("#id"), whenever I need the element.
If needed I can provide more informations or snippets.
I am thankfull for each explanation, why this is slowing down my app.
If it's a mobile html5 app why are you using jQuery for selectors? Seems very redundant.
I usually do somthing along the lines of this:
// helpers, since i hate typing document.get ..
function _id(e){ return document.getElementById(e); } // single id
function _all(e){ return document.querySelectorAll(e); } // single elem
function _get(e){ return document.querySelector(e); } // multiple elem
// loop helper (for changing or doing things to collection of elements)
function _for(e,f) { var i, len=e.length; for(i=0,l=len;i<l;i++){ f(e[i]); }}
// VARs (global)
var c = _id('c'), // main selector
box = c.querySelectorAll('.box'), // boxes in 'c'
elements = box.querySelectorAll('.element'); // elems in 'box'
// Change background-color for all .box using the _for -helper
_for(elements, function(e){ e.style.backgroundColor = 'red'; }
I only store main parents of elements so that i can then query down the DOM if needed (limiting the lockup needed for traversing). In the example variables above one could imagine that something in the .box would change several times OR that .box is a slow selector.
Do note that global variables increase memory usage though since those variables can interfer with garbage collection. Also note that objects can be slower in some browsers and if it doesn't bloat your code to much you should instead store it more plainly (you shouldn't store too many global variables anyway so....).
Edit, jsPerf:
http://jsperf.com/global-vs-local-vars-14mar2015
Do note however that depending on what you're selection and exactly what you're doing will have the greatest impact. In the jsPerf-example the difference between local and global quickly diminishes as soon as one starts selecting descendants from the globally cached selectors ie doing box.find('p').css('color','blue') etc.
This is quite old but we never know, someone can read this post.
jQuery is based on Sizzle which is way smaller: https://sizzlejs.com/
You can eventually include only this library. I would not recommend to maintain your own piece of code for this purpose. It is already done and maintained by someone else.
Related
As part of a Chrome extension I am searching the entire DOM for elements containing specific words inside each ID/Class.
Currently it looks something like:
"allSelectors": document.querySelectorAll("[id*='example'][class*='example']"),
"collapse": function () {
for (var i = 0; i < MyObject.allSelectors.length; i++) {
// Manipulate MyObject.allSelectors[i] etc
}
},
First, I would like to restructure it somehow (possibly using an array?) so that it is easy to add new selectors as doing it like this:
document.querySelectorAll("[id*='example'][class*='example'][id*='other'][class*='other']")
Isn't easily scaleable or good.
Secondly, I think document.querySelectorAll is very slow - the reason I am using it is because I need to search anywhere in an id/class (hence the use of *=) and cannot use a big external library (such as jQuery), as this is a small file and is being injected user side.
Is there an any solution to either of these problems? because if there are many matches then this slowness might become an issue.
First of all I would totally go for querySelectorAll, I don't think it's that slow, and also it totally fits in a situation like yours. I agree with you that adding a library is overkill for this, and additionally it might not be as beneficial as someone thinks (let's test it here).
Then, again I agree with you that the current solution is not very scalable and that the array is the way to go. Here's a very basic implementation using an array:
// an array of classes and ids to match
var nodes,
searches = [
'[id*="test"]',
'[class*="example"]'
];
// a simple function to return an array of nodes
// that match the content of the array
function getNodes(arr){
return Array.prototype.slice.call(document.querySelectorAll( arr.join() ));
}
nodes = getNodes(searches);
The good thing is that new classes and ids can be easily added or removed from the array, for example, later on you can add:
searches.push('[id*="some"]');
nodes = getNodes(searches); // new nodes will be fetched
Here's a jsbin with a full example code.
//Following function add new table entry to table
//and return interface which has function which uses closure to access and update the table
var _newRow = (function(){
var _interface = {
updateName: null,
updateProgress: null,
actionLinkButton : null,//<a> tag used for user aciton to perform on UI like delete, hide, show etc.
..
..
..
};
var tr = createTr();
var tdName = createTd();
_inteface.updateName = function(newName){
tdName.innerHTML = newName;
}
..
..
..
..
..
return _interface;
})(tblObject);
//maintaining the array of all the rows as per row number
rowArray[rowNo] = _newRow;
..
..
//using the row array to update the entries
rowArray[rowNo].updateProgress('read');
Above is the pattern i have used to update the dynamically added rows on the client end. What i do is to while adding row to the table create _interface, return it and store it as per row number.
However for this i have used closure means many alive objects. I would like to know is this correct way ? Is there better approach that this ? What profiling tools i can use to know how much memeory this code is using ? How can i ensure that closures are cleared properly when they are not needed ?
JavaScript has a garbage collector which will collect stray objects and deallocate them for you automatically. There is no way to control when or how.
What may prevent objects/closures from being garbage collected is when you have globally accessible objects referencing functions with lexical scope. Make sure you detach all values you don't use (for instance, remove them from the DOM). If you're sure there is no way to access the values they will eventually be garbage collected.
To identify memory leaks it's important to not optimize prematurely, you can monitor the memory usage of your web browser. If it isn't noticeable there then you probably don't need to worry about it. You may want to simulate a lot of operations in your app, to see what the state might look like after the app has been running for a long time.
But generally, don't worry about memory usage. It is in my experience very rarely an issue.
Code 1:
$("#page").replaceWith(html_string)
Code 2:
$("#page .title").text("Hello")
I am starting to use Mustache.js, jQuery.tmpl, and Coffeekup and am starting to wonder what best practices are in terms of re-rendering html elements.
Say I have a list of items, like here, and I want to just change the titles/tags/images with JSON via a templating framework. Should I:
Replace the whole list itself with a new html string?
Replace each list item with a new html string?
Replace just the text/attributes in every single element with the json values?
I know the last case will require traversing the dom a lot more, but I'm not sure if that's more of a performance hit than replacing the whole html tree. How does this work?
I tend to think that you shouldn't destroy DOM elements just to recreate them immediately.
The last case doesn't really add any DOM traversal, but it does modify the DOM several times instead of just once.
If you're concerned about performance you can always use the detach()[docs] method to remove the elements from the page, do your manipulation on its content, then append them.
// reference the container
var ul = $('#myul');
// select and detach the children
var lis = ul.children().detach();
// do your manipulation
lis.each(function() {
// update the text
});
// reinsert them
ul.append(lis);
The .detach() will keep the elements and all their handlers/data intact while you manipulate them.
A jQuerytmpl template is a compiled javascript function, which should be even faster then rendering html strings.
Imagine the browser. It reads first all the html and parses it then. With a jquery template you go one step further and provide the browser the already parsed object.
Compiled templates like jQuery.tmpl are the fastest way i think, faster than any html, if coded good.
Waiting for critics SO! :)
no different
for Code 1:
$("#page").replaceWith(html_string)
Code 2:
$("#page .title").text("Hello")
I'm wondering which of the following jQuery queries is going to be faster. I'm looking to match any span tags that have either an src attribute or a data-src attribute.
var a = $('span[src],span[data-src]');
var b = $('span').filter('[src],[data-src]');
My gut feeling is (b) but there may be optimisations I'm not aware of.
Thanks.
UPDATE:
Based on a quick test with 100 x span[src], 100 x span[data-src], and 100 x span elements: (a) came out around 4 - 8 times faster depending on the browser. On IE8 it was a lot faster (about 50 times) and on IE6/7 about the same.
What I'm wondering is why is it faster?
In case (a) jquery delegates the entire selector query the native querySelectorAll where available. So what looks like a slower query is actually very fast on modern browsers.
At http://jsfiddle.net/B9Vmy/1/ i ran some tests (use firebug for the console stuff)
for 6000 spans (2000 spans,2000 with src,2000, 2000 with data-src) this ran in about 8ms so the selection part is neglectable. What makes this so slow is the creation of the jQuery objects (jQuery(element)).
While A does that only once for only the returned results, B does it for every element, after that uses those results and does that again for the returned results.
And then there's the sizzle engine possibly being used for selecting the elements... Take a look at the Filter timing for a laugh :-)
It is just a hypothesis, more based on logic than test.
In first case, the selector will select the span with src attribute.
In second case, the selector will select all span and then filter span with attr src.
So, first will be faster.
If I am wrong, correct me
The first version will do two passes of the complete DOM tree; whereas the second one only once.
The real answer requires a profiling on your specific case i.e. depending on how complex your DOM is. Also, different jQuery version might result in different results.
I am writing a jQuery plugin and I am at the optimization stage.
I wonder which of these leads to a quicker script in general, and what sort of mitigating factors are important:
Have the script generate lots of classes and ids at the start so finding elements in the dom is easier (quicker too?) later on.
Keep classes and ids to a minimum (so save time by not creating them), but then look for elements in more convoluted ways later (eg the nth item in an object), which I presume is slower than getting by id/class.
The way the browser works is that upon load it creates an in-memory DOM tree which looks as follows:
P
_______________|______________
| |
childNodes attributes
______________|___________ |
| | | title = 'Test paragraph'
'Sample of text ' DIV 'in your document'
|
childNodes
__________|_______
| | |
'HTML you might' B 'have'
So when you lookup P > DIV > B, the lookup has to find all P elements, then find all DIV elements within P and then find all B elements within DIV. The deeper the nesting the more lookups it needs to do. Further, it might find all P > DIV only to find that none of them have B and it will have wasted time looking through all P > DIV matches.
Lookups by ID are faster because IDs are guaranteed to be unique so the DOM can store them as hash table entries which have very fast lookups. In terms of jQuery the implementation might be slightly different, however, document.getElementById has the fastest lookup time so $('#my_node_id') should also be quite fast.
Consequently, if your node doesn't have an ID, you can find the nearest ancestor that does and find your node relative to that ancestor
#my_node_id > div > b
because the look up only needs to happen under the sub-tree of #my_node_id it will be faster than p > div > b
The question is not really specific enough so I can give you advice directly relevant to your code, but here are some of my favorite jQuery optimization tips:
Whenever possible, specify a context! Don't make jQuery look places it doesn't have to. If you know that something is going to be inside the #container div, then do $(something, '#container');
.myclass is slow. Internally, jQuery has to go through every single element to see if it has the class you are searching for, at least for those browsers not supporting getElementsByClassName. If you know that a class will only be applied to a certain element, it is way faster to do tag.myclass, as jQuery can then use the native getElementsByTagName and only search through those.
Don't do complicated selectors in one bang. Sure, jQuery can figure out what you want, but it takes time to parse out the string and apply the logic you want to it. As such, I always like to separate my "queries" out into patches. While most people might do $('#myform input:eq(2)'); or something like that, I prefer to do $('input','#myform').eq(2); to help jQuery out.
Don't re-query the DOM if you plan on doing multiple things with a set of objects. Take advantange of chaining, and if not possible to use chaining for whatever reason, cache the results of the query into a variable and perform your calls on that.
I think you answered your own question: 'convoluted ways' is a synonym for 'it will break' - any changes to the html structure will break your code.
For example, imagine you're trying to get myDiv and you assume it's the last sibling of child:
<div>parent
<div>child</div>
<div>myDiv</div>
</div>
What happens if you later decide the structure should really be like this?
<div>parent
<div>child</div>
<div>myDiv</div>
<div>child</div>
</div>
By relying on assumptions about structure your code becomes really brittle. Adding classes and ids to nodes will prevent such scenarios.
I think you should go with the first choice. Do also remember that getting nodes by class is always slower than getting them by id.
With my plugins I try, as best I can, to limit the amount of hooks I introduce into the document. By "hooks" I mean IDs or classes.
The best way to avoid them completely is to retain references to any created elements within your plugin's closure. For example:
jQuery.fn.addList = function(items, fn){
var $list = $('<ul/>').html('<li>' + items.join('</li><li>') + '</li>');
return this.each(function(){
$(this).append($list);
fn.call($list);
});
};
$('body').addList(['item 1', 'item 2'], function(){
var referenceToTheList = this;
console.log(referenceToTheList, '<- this is my list, no hooks involved!');
});
The list can be carried around JavaScript functions (referenced and used in multiple places) without requiring any hooks in the HTML; thus making it as unobtrusive as possible!
Avoiding/limiting hooks is especially important in plugin development because you never know where it might end up being used.