Related
I was recently assigned a very small but complex task in jQuery, the requirement was quite simple, given the following HTML :
<div>
<span id="myid2151511" class="myclass23462362">....foobar....</span>
<span id="myid2151512" class="myclass23462362">....YoLO....</span>
<span id="myid2151513" class="myclass23462362">....lalal....</span>
<span id="myid2151514" class="myclass23462362">....foobar....</span>
</div>
What i have to do i recursively go through all the span under div, With a certain id and check if the values contained in the spans is foobar, So i can up with the following jQuery code:
$(function(){
$('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' })
});
FIDDLE HERE
Its quite a complex bit of code by itself, but the jQuery documentation made it a cakewalk for me as for as understanding the code is concerned.
By now i am comfortable writing code like so in jQuery:
$('some-Element').somemethod().anothermethod().yetanothermethod();
Every function returns a value in the above jQuery statement, so chain ability becomes a reality.
but when i see code like so.
$('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' });
I am thrown a bit off the hook(although i managed to write the above line myself), notice how alot of the filtering is done by a selector :last and :contains, to me they appear to be working much like some kind of a jQuery method. So my question is, how do these selectors in jQuery work in comparison to jQuery methods ?
If anybody could explain or give me a vague idea, it would be Fantastic.
EDIT ::
well to clarify my question in one line, to me $(".someClass").eq('10'); makes sense, but somehow $(".someClass:eq(10)") does't , i mean it works, but how on earth is it implemented internally ?(I wrote this edit after reading the answers below, and well this question has been thoroughly answered by now, but this edit is just to clarify my question.).
That's an interesting question. The short answer is they both accomplish the same thing. Of course though, there's always more to the story. In general:
$('div [id^="myid"]:contains("foobar"):last').css({'background' : 'rgb(227, 216, 22)' });
Is equivalent to:
$("div").find("[id^='myid']").filter(":contains('foobar')").last().css({'background' : 'rgb(227, 216, 22)' });
Most of the time when you call $(), jQuery is calling document.querySelectorAll(). This is a browser implemented function that grabs elements based on a selector. That complex string you create is passed to this method and the elements are returned.
Naturally, things implemented by the browser are faster than JavaScript so the less JavaScript and more C++, the better. As a result, your example passing everything as a selector is likely to be faster as it just sends it all to the browser as one call and tells it "do it." Calling $(), contains(), last() on the other hand is going to call querySelectorAll multiple times and therefore it will likely be slower since we're doing more JavaScript as opposed to letting the browser do the heavy lifting in one shot. There are exceptions though. JQuery generally calls querySelectorAll. However, there are times when it doesn't. This is because jQuery extends what querySelectorAll is capable of.
For example, if you do something like $(".someClass:eq(10)") per the jQuery documentation:
jQuery has extended the CSS3 selectors with the following selectors. Because these selectors are jQuery extension and not part of the CSS specification, queries using them cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using these selectors, first select some elements using a pure CSS selector, then use .filter().
So in that case, while $(".someClass:eq(10)") might seem to be faster, in reality $(".someClass").eq(10) or $(".someClass").filter(":eq(10)") is going to be faster since the first call will be executed as JavaScript code. The latter two will first call querySelectorAll to select by class, then only use JavaScript to find the 10th element. When jQuery has to do the selection in pure JavaScript, it does it using the Sizzle engine which is fast, very fast, but not faster than native code in the browser. So again, the short answer is, they're the same thing, the long answer is, it depends. If you're interested in all the extensions that fall into that category, the link to the jQuery documentation I included lists them.
First of all, yes nikhil was right. ID is unique identifier and can be only used once. If you are willing to apply same styles to several elements, or you to use it to select several elements together use class attribute. But however, i couldn't understand your question. But maybe this could help
there is function in javascript which is widely supported by almost all major browsers
document.querySelectorAll("div [id^=myId]");
in fact you could write your own library (well not as advanced one like jquery but)
var $ = function(selector){
return document.querySelectorAll(selector);
}
// and then you could use it like this
var elementsWithMyId = $("div [id^=myId]");
// where elementsWithMyId will contain array of all divs which's id start with myId
so as i understood your question, No. there is no magic happening behind jQuery selections it's just browser built in function which is kinda shortened by jquery. of course they added tons of new features, which would work like this:
var $ = function(selector){
var elementsArray = document.querySelectorAll(selector);
elementsArray.makeBlue = function(){
for(var i = 0; i < elementsArray.length; i++){
elementsArray[i].style.backgroundColor = "blue";
}
// so elementsArray will now have function to make all of its
// div blues. but if you want to have chain like that, we have to return this array not just make all of it blue
return elementsArray;
}
elementsArray.makeRed = function(){
for(var i = 0; i < elementsArray.length; i++){
elementsArray[i].style.backgroundColor = "red";
}
return elementsArray;
}
return elementsArray;
}
// so now you can use it like this
// this returns array which has options make blue, and make red so lets use make blue first
// makeBlue then returns itself, meaning it returns array which has again options of making itself red and blue so we can use makeRed now
$("div [id^=myId]").makeBlue().makeRed();
and thats it!
I am curious as which selector would be quicker for the browser to look up. I am interested in general rather than specific browsers.
$('accountDetailsTable').getElements('.toggler')
This will look for accountDetailsTable as if you were using document.getElementById('accountDetailsTable'); and then look for .toggler inside of the element.
$$('.toggler')
Whereas this one will return all the selectors directly. But ultimately they will both give me the same result.
So which one would be quicker? How could I test this?
performance of selectors will differ between browsers significantly. eg. with querySelector and querySelectorAll (QSA) vs without. When without QSA, with getElementsByClassName or without.
the amount of work that the selector engine needs to do will vary.
you can write this differently. 3 ways to do so, not just 2:
1. $('accountDetailsTable').getElements('.toggler')
anatomy of the above is:
get element (1 call).
call method getElements from element prototype (or element directly in old IE)
look for all childNodes that match the class selector
this will be consistent in browsers in that it gets a root node and calls methods off it. if no QSA, it will go to getElementsByClassName or walk all childNodes and filter the className property until it has a list of matches. Performance wise, this will be worse in modern browsers because it needs to chain whereas method 3 will be a direct result.
because of how selectors work in JS, unlike in CSS - it's from left to right and more qualified selectors improve performance, having something like .toggler means when there is an older browser, it needlessly needs to consider every single DOMnode in the tree (except for text nodes). always qualify the selectors when you can, i.e. div.toggler or a.toggler.
2. $$('.toggler')
if QSA is available, rely on the browser to return stuff (no extra hacks here like :not, or :contains or :has or ! (reverse combinators).
if NO QSA, it will parse the expression via the Slick parser and basically internally degrade to something like in case 1 above. The biggest difference here is the lack of context - it will run against the whole document as $$ internally does something like document.getElements('.toggler') so there are a lot more nodes to consider. Always anchor your queries to a stable upper-most common node. or pass it into the query string for qualification like in case 3
once again, this will be improved for performance by making it more qualified eg:
$$('a.toggler')
3. $$('#accountDetailsTable .toggler')
Similar to case 2 but when QSA is available, it will be faster.
When QSA it is not there, it will run against the context of the #accountDetailsTable node so it will be better than case 2.
Making this more qualified will make a difference:
$$('#accountDetailsTable td.control > a.toggler')
big discount: it will depend on how big your DOM is, how many matches are found and returned. on a simple DOM, the expected performance order may differ.
Performance optimisations of selectors are increasingly irrelevant these days.
The days of SlickText comparisons of frameworks are over and application performance has have little to do with selector speed, or you are doing something wrong.
If you do your job right, you won't need to be constantly selecting elements. You can cache things, reuse, be smart and reduce DOM lookups to a minimum.
Events etc can be attached through smart event delegation, where appropriate, completely negating the need to select and add events to multiple nodes etc - use common sense and don't get hung up on theoretical performance benchmarks. Instead, use a profiler and test your actual app and see where you lose time / CPU cycles.
You can run a simple selector like that over 50000 times in the space of a second. That's micro-benchmarking and does not measure actual real world performance inside your APP, DOM, browser etc.
More thoughts on benchmarking performance and premature optimisations: http://www.youtube.com/watch?v=65-RbBwZQdU
Careful
Write for correctness and readability first. Even if you can get extra performance by doing something, don't do it at the expense of readability if it's not critical / reused all the time. Selectors like .toggler, .new, .button etc tend to be too generic and can be re-used across the app in different parts of the DOM. You need to qualify selectors to also ensure your intended functionality will continue working when it gets moved into a different page / widget / DOM and your project gets an influx of new developers.
just my two cents, I know you already accepted the answer.
My internal MooTools knowledge got kind of rusty over the last two years, but generally speaking I expect the $$-selector to be much faster, since it has to run through the elements only once.
Why not give it a try? See this JSfiddle:
Rough HTML:
<div id="accountDetailsTable">
<div id=".toggler">1</div>
<div id=".toggler">2</div>
<div id=".toggler">3</div>
</div>
JScript (please don't comment on the bad code, its just to demonstrate the functionality):
window.addEvent('domready', function() {
var iter = 50000;
var tstart = new Date().getTime();
for (var i=0;i<iter;i++) {
var x = $('accountDetailsTable').getElements('.toggler');
}
var tend = new Date().getTime();
var tdur = tend - tstart;
console.log('$: ' + tdur + ' ms');
var tstart = new Date().getTime();
for (var i=0;i<iter;i++) {
var x = $$('.toggler');
}
var tend = new Date().getTime();
var tdur = tend - tstart;
console.log('$$: ' + tdur + ' ms');
});
That said, my tests with about 50000 iterations lead to roughly this results:
$('accountDetailsTable').getElements('.toggler') : ~ 4secs
$$('.toggler') : ~ 2secs
Results will vary across browsers, elements and much more, so this is only a rough approximation.
This said, you'll probably feel only a difference if you have that many selectors in such a short period. Yes, performance should be thought about, if you only have a few selectors in your application, it shouldn't really matter.
I prefer the $$(), not because of the better performance, but because of better readability.
I been searching but I can only find articles talking about one or the other. Which one is better?
I'm making a small web app where performance is not a big concern since there's nothing complex going on.
I considered using jQuery's val() function since maybe it solves some inconsistency I'm not aware of, but getElementById.value IS faster (although the end user won't notice.)
So which one should I use? Is jQuery's non-native method worth the lower performance to gain more compatibility?
The biggest advantage of using jQuery().val() over document.getElementById().value is that the former will not throw an error if no elements are matched, where-as the latter will. document.getElementById() returns null if no elements are matched, where-as jQuery() returns an empty jQuery object, which still supports all methods (but val() will return undefined).
There is no inconsistency when using .value for form elements. However, jQuery.val() standardises the interface for collecting the selected value in select boxes; where as in standard HTML you have to resort to using .options[this.selectedIndex].value.
If you're using <select> elements as well, .value won't work whereas .val() will.
I would not mind about performance of just getting a value. If you want the best performance, perhaps you shouldn't use a library at all.
jQuery does so many nice little error handling things (look below) that I would never write a line of javascript without jquery in a browser again.
First, val works on checkbox groups, selects, gets html, and the
like.
Second, $ lets you use sizzle selectors, so in the future, you can
easily switch between an ID and a CSS path.
Third, your code will be so much easier to read and maintain if you
just use jQuery, that the time you save maintaining your code
outweighs any speedup that you admit your users won't see. Finally,
jQuery is a very popular, very widely used library. They will make
$ and val as fast as they can.
I think using pure Javascript is quicker for the following reasons:
You won't have to learn more than pure js
If you don't want errors, use catch(exeption) (I think...)
You don't have to put in that little extra time to type in the code to initiate jquery
The browser responds quicker if you don't use jquery
Normal js works (in a better way) on checkboxes #johndodo
Thank you for listening to my answer.
I've been looking into the performance differences with this recently and, slightly unsurprisingly, using vanilla JS to grab a value is faster than using jQuery. However, the fallbacks that jQuery provides to prevent errors, like what #Matt mentioned, is very useful. Therefore, I tend to opt for the best of both worlds.
var $this = $(this),
$val = this.value || $this.val();
With that conditional statement, if this.value tries to throw an error, the code falls back to the jQuery .val() method.
Here https://www.dyn-web.com/tutorials/forms/checkbox/same-name-group.php is an implementation for checkboxes, apparently options just need to be named the same with the array brackets notation in the name i.e.: name="sport[]" then yu get the array inJavascript via: var sports = document.forms['demoForm'].elements['sport[]']
I was looking for a selection type field solution without using jQuery and I came across this solution:
The Selection group is an object: HTMLCollection, and it has a lenght method and a selectedOptions property, which allows you to iterate through its label properties to populate an Array with the selected options, which then you can use:
...
vehicleCol = document.getElementById('vehiculo').selectedOptions;
vehiculos = [];
if (vehicleCol !== undefined) {
for (let i = 0; i < vehicleCol.length; i++) {
vehiculos.push(vehicleCol[i].label.toLowerCase())
}
}
...
I'd use jQuery's val(). Shorter code means faster download time (in my opinion).
This problem is about Javascript writing HTML code for video player. I think there are some faster methods(document.createElement,Jquery and etc). Please tell some better and faster methods for this procedure. Thanks in advance
function createPlayer(videoSource){
document.writeln("<div id=\"player\">");
document.writeln("<object width=\"489\" height=\"414\" >");
document.writeln("<param name=\"player\" value=\"bin- debug/FlexPlayer.swf\">");
//etc
document.writeln("</embed>");
document.writeln("</object>");
document.writeln("</div>");
}
Going native with document.createElement will be the fastest. However, if your markup is large, going this way makes it a maintenance nightmare. Also, it is not easy to 'visualize' things.
In those cases, you might want to go for a tradeoff with client side templating solutions such as jQuery templates or underscore templates or John Resig's microtemplating.
Another performance boost is to build your entire markup and add it to DOM at the very end (add children first, then add the parent to DOM).
There is a jQuery function I know of that allows you to create a template HTML snippet which you can later use repeatedly with only 1 or 2 lines of code, adding in variables and appending it to the page.
For this you will need jQuery (latest should be fine) http://jquery.com/
Docs for the tmpl function are here: http://api.jquery.com/jquery.tmpl/
For details on how to use it you'd be best reading an example on the jQuery docs, I've not used it myself so can't write you a good example but there is great stuff on the docs site.
Hope this helps
EDIT:
A less resource intensive way to acheive that function would be to, rather than writing each line in turn to the document, just append them all to a string and then write that once when you are finished.
Eg:
function createPlayer(videoSource){
var html="<div id=\"player\">";
html+="<object width=\"489\" height=\"414\" >";
//etc
document.writeln(html);
}
This is faster because writing a line to the document uses more resources than just appending a string in memory. For MAXIMUM SPEED you could even declare the html var outside of the function and just set it to the markup as one long string, then write it - i.e
var html;
function createPlayer(videoSource){
html="<div id=\"player\"><object width=\"489\" height=\"414\" >"; //and so forth
document.writeln(html);
}
If you can justify the larger download sizes I'd go for the jQuery solution if possible, it's generally a bit more manageable - I've done plenty script generated HTML in the past and it very quickly becomes a pain to maintain. Good luck
You can try this:
function createPlayer(videosource){
var div = document.createElement('div');
div.innerHTML = '<object width=\"489\" height=\"414\" >' +
'.......'
document.body.appendChild(div);
}
For general manipulation and addition of HTML I'd recommend jQuery. It makes the process much easier and quicker.
You will find more information on this here:
jQuery Manipulation Methods - http://api.jquery.com/category/manipulation/
jQuery Tutorials - http://docs.jquery.com/Tutorials
This question already has answers here:
Deep cloning vs setting of innerHTML: what's faster?
(2 answers)
Closed 8 years ago.
I'm looking at a problem that needs a complex block of divs to be created once for each element in a set of ~100 elements.
Each individual element is identical except for the content, and they look (in HTML) something like this:
<div class="class0 class1 class3">
<div class="spacer"></div>
<div id="content">content</div>
<div class="spacer"></div>
<div id="content2">content2</div>
<div class="class4">content3</div>
<div class="spacer"></div>
<div id="footer">content3</div>
</div>
I could either:
1) Create all the elements as innerHTML with string concatenation to add the content.
2) Use createElement, setAttribute and appendChild to create and add each div.
Option 1 gets a slightly smaller file to download, but option 2 seems to be slightly faster to render.
Other than performance is there a good reason to go via one route or the other? Any cross-browser problems / performance gremlins I should test for?
...or should I try the template and clone approach?
Many thanks.
Depends on what's "better" for you.
Performance
From a performance point of view, createElement+appendChild wins by a LOT. Take a look at this jsPerf I created when I compare both and the results hit in the face.
innerHTML: ~120 ops/sec
createElement+appendChild: ~145000 ops/sec
(on my Mac with Chrome 21)
Also, innerHTML triggers page reflow.
On Ubuntu with Chrome 39 tests get similar results
innerHTML: 120000 ops/sec
createElement: 124000 ops/sec
probably some optimisation take place.
On Ubuntu with QtWebkit based browser Arora (wkhtml also QtWebkit) results are
innerHTML: 71000 ops/sec
createElement: 282000 ops/sec
it seems createElement faster in average
Mantainability
From a mantainability point of view, I believe string templates help you a lot. I use either Handlebars (which I love) or Tim (for project which need smallest footprints). When you "compile" (prepare) your template and it's ready for appending it to the DOM, you use innerHTML to append the template string to the DOM. On trick I do to avoid reflow is createElement for a wrapper and in that wrapper element, put the template with innerHTML. I'm still looking for a good way to avoid innerHTML at all.
Compatibility
You don't have to worry here, both methods are fully supported by a broad range of browsers (unlike altCognito says). You can check compatibility charts for createElement and appendChild.
Neither. Use a library like jQuery, Prototype, Dojo or mooTools because both of these methods are fraught with trouble:
Did you know that innerHTML on tables for IE is readonly?
Did you know for the select element it's broken as well?
How about problems with createElement?
The writers of the major javascript libraries have spent a lot of time and have entire bug tracking systems to make sure that when you call their DOM modifying tools they actually work.
If you're writing a library to compete with the above tools (and good luck to you if you are), then I'd choose the method based on performance, and innerHTML has always won out in the past, and since innerHTML is a native method, it's a safe bet it will remain the fastest.
altCognito makes a good point - using a library is the way to go. But if was doing it by hand, I would use option #2 - create elements with DOM methods. They are a bit ugly, but you can make an element factory function that hides the ugliness. Concatenating strings of HTML is ugly also, but more likely to have security problems, especially with XSS.
I would definitely not append the new nodes individually, though. I would use a DOM DocumentFragment. Appending nodes to a documentFragment is much faster than inserting them into the live page. When you're done building your fragment it just gets inserted all at once.
John Resig explains it much better than I could, but basically you just say:
var frag = document.createDocumentFragment();
frag.appendChild(myFirstNewElement);
frag.appendChild(mySecondNewElement);
...etc.
document.getElementById('insert_here').appendChild(frag);
Personally, I use innerHTML because it's what I'm used to and for something like this, the W3C methods add a lot of clutter to the code.
Just a possible way to cut down on the number of div's however, are there any reasons you are using spacer elements instead of just editing the margins on the content divs?
I don't think there's much to choose between them. In the olden days (IE6, FF1.5), innerHTML was faster (benchmark), but now there doesn't seem to be a noticeable difference in most cases.
According to the mozilla dev. docs there are a few situations where innerHTML behaviour varies between browsers (notably inside tables), so createElement will give you more consistency - but innerHTML is usually less to type.
Since you mentioned template and clone, you may be interested in this question:
Deep cloning vs setting of innerHTML: what’s faster?
Another option is to use a DOM wrapper, such as DOMBuilder:
DOMBuilder.apply(window);
DIV({"class": "class0 class1 class3"},
DIV({"class": "spacer"}),
DIV({id: "content"}, "content"),
DIV({"class": "spacer"}),
DIV({id: "content2"}, "content2"),
DIV({"class": "class4"}, "content3"),
DIV({"class": "spacer"}),
DIV({id: "footer"}, "content3")
);
Personally, if each item is going to need the exact same structure created I would go with the cloning approach. If there's any logic involved in creating the structure into which the content will go, I'd rather maintain something like the above than fiddling about with strings. If that approach turned out to be too slow, I'd fall back to innerHTML.
Neither. Use cloneNode.
var div = document.createElement('div');
var millionDivs = [div];
while (millionDivs.length < 1e6) millionDivs.push(div.cloneNode())
As I know, the fastest way is to evade DOM editing as long as it is possible. That mean, it is better to create a big string and then put it into innerHTML. But there is a remark for this: don't make too many operation on big strings, it is faster to use array of strings and then join them all.
For a complex problem like this, I usually use the innerHTML methods because they are a)easier to read and modify code-wise b)more convenient to use in loops. As the top post says, they unfortunately fail in IE(6,7,8) on <table>, <thead>,<tbody>,<tr>,<tfoot>, <select>, <pre> elements.
1) Create all the elements as innerHTML with string concatenation to add the content.
2) Use createElement, setAttribute and appendChild to create and add each div.
3) compromise. Create all the elements in one go as innerHTML (which avoids a lot of childnode list manipulation slowness), then write the content that changes on each item using data/attribute access (avoiding all that nasty mucking around with having to HTML-escape content). eg. something like:
var html= (
'<div class="item">'+
'<div class="title">x</div>'+
'<div class="description">x</div>'+
'</div>'
);
var items= [
{'id': 1, 'title': 'Potato', 'description': 'A potato'},
{'id': 2, 'title': 'Kartoffel', 'description': 'German potato'},
// ... 100 other items ...
];
function multiplyString(s, n) {
return new Array(n+1).join(s);
}
var parent= document.getElementById('itemcontainer');
parent.innerHTML= multiplyString(html, items.length);
for (var i= 0; i<items.length; i++) {
var item= items[i];
var node= parent.childNodes[i];
node.id= 'item'+item.id;
node.childNodes[0].firstChild.data= item.title;
node.childNodes[1].firstChild.data= item.description;
}
Can also be combined with Neall's tip about DocumentFragments.