Today i'm very stack with a Work and jQ. I was get a morning for it but i can't resolve it :(.
My Work here:
<div class="container">
<p class="test">a</p>
<div>
<p class="test">a</p>
</div>
</div>
In normal, i can using jQ with each function for select all <p class="test">a</p> EX:
$(".test").each(function() {
$(this).text('a');
});
But i hear everyone talk that, for function get a less timeload than each function. Now i want using for instead of each.. but i don't know how to write code jQ in this case.
Somebody can help me!. thankyou!
I wouldn't worry about it unless you were iterating through hundreds of them.
for loop is usually used with normal DOM (aka without jQuery) traversing, like...
var elements = document.getElementById('something').getElementsByTagName('a');
var elementsLength = elements.length;
for (var i = 0; i < elementsLength; i++) {
elements[i].style.color = 'red';
}
Caching of elementsLength is a good idea so it is not calculated every iteration. Thanks to CMS for this suggestion in the comments.
Just adapt that for your jQuery object if you wanted to do it with jQuery.
Replace elements variable with your jQuery collection, like $('#something a'). I think you may need to rewrap the object if you need to do any more jQuery stuff with it.
One thing to watch out for is that using an ordinal accessor on the result of a jQuery selection will return a native DomElement. If you want to use jQuery methods on them, you have to re-wrap them:
var testElements = $('.test');
for (var i = 0; i < testElements.length; i++) {
// Using $() to re-wrap the element.
$(testElements[i]).text('a');
}
I'd second what others have said though. Unless you're dealing with many elements, this is premature optimization. Re-wrapping the elements to use the .text() method may even bring it back to no gain at all.
have you tried the obvious solution?
var nodes = $(".test");
for(var i = 0; i < nodes.length; i++)
{
var node = nodes[i];
}
This article shows that each() has no significant performance penalty until you get into the hundreds of thousands of looped-over items.
Another alternative:
for (var i = 0; i < $('.test').length; i++){
var element = $('.test').eq(i);
}
Related
I am making a game and using hundreds of lines of
document.getElementById("ID").innerHTML = someVariable;
to update everything I calculated with functions. How could I make it better or is this the best method? I can't really use loops for it like
for (var i = 0; i < IDs.length; i++) {
document.getElementById("IDs[i]").innerHTML = Variables[i];
}
beacuse I have so much different variables and diferent ids.
So should I rework everything into arrays and use them or what?
Thanks for any advice!
There are several things that you might do improve performance a little. Unfortunately jsperf is down for maintenance at the moment, but I'm not sure that it would help much because the efficiency of DOM manipulations varies so widely between browsers and the particulars of an application.
The first thing I would suggest is a set of "micro efficiencies" which may not even help much but are good practice nonetheless. Keep an array of references to your DOM elements so you don't have to call getElementById often. While getElementById is very fast, it is still a function call which can be avoided. You might think that the array will take up a lot of memory, but you aren't actually storing the DOM elements in the array but rather storing pointers to DOM elements. Also, you can also keep a reference to the length of items so that it's not calculated on every loop iteration:
const myDivs = [/* populate this array with your DOM elements */];
for (var i = 0, l = IDs.length; i < l; i++) {
myDivs[i].innerHTML = Variables[i];
}
Another thing which is important is to wait for an animation frame before doing a heavy DOM manipulation. You can read more about requestAnimationFrame here.
Finally, you are just going to have to test. As someone suggested in a comment your best bet is to do direct DOM manipulation without using innerHTML. The reason for this is because innerHTML requires parsing and render tree construction which is expensive. An example of direct DOM manipulation would be... let's say you want to go from this state:
<div id="ID[1]">
<img src="foo.jpg" />
</div>
... to this state:
<div id="ID[1]">
<h1>Hello</h1>
<img src="foo.jpg" />
</div>
We just added an H1 - you would write something like this:
const h1 = document.createElement('h1');
h1.innerText = 'Hello';
const div = document.getElementById('ID[1]');
div.insertBefore(h1, div.firstChild);
But as you can see, this requires you to do a "diff" between the before and after states and calculate the most efficient way to get from one to the other. It just so happens that this is what ReactJS and other Virtual DOM libraries do very efficiently - so you might try out one of those libraries.
If you are against using a library or think that your DOM will fluctuate too much for in-memory diffing to be efficient, then you might try constructing a DOM string and using innerHTML as few times as possible. For example, if your DOM looks like this:
<div id="main-container">
<div id="ID[1]">...</div>
<div id="ID[2]">...</div>
<div id="ID[3]">...</div>
...
</div>
Then try doing something like the following:
let html = '';
const container = document.getElementById('main-container');
for (let i = 0, l = IDs.length; i < l; i++) {
html += `<div id="ID[${i}]">${Variables[i]}</div>`;
}
// you want to set innerHTML as few times as possible
container.innerHTML = html;
I have my own implementation of dropdown list. I am storing all list identifiers in the global array and on window click event I am iterating through this array and deciding which list I have to hide.
I need to check if element has ancestor with .active class.
jQuery version:
for (var i = 0; i < window.dropdowns.length; i++) {
var e = window.dropdowns[i];
if ($(event.target).closest('.active').length == 0) {
e.hideList();
}
}
Pure javascript version:
for (var i = 0; i < window.dropdowns.length; i++) {
var e = window.dropdowns[i];
var parent = event.target.parentElement;
while (parent.tagName != 'BODY') {
if (parent.className.indexOf('active') > 0) {
e.hideList();
break;
}
parent = parent.parentElement;
}
}
So, what version of this will be faster? And how performance depends on number of elements on the page?
If you just want to know what's fastest, write a simple test to find out. If you want to know why...
jQuery is going to do more work than you need, for example, you are only testing tagName and className.
Having said that, your code could give you false positives because className.indexOf('active') will return > -1 if the element has a class of notactive. Use classList instead.
Finally, if you are already using jQuery, you should use it since we just showed you that code we write ourselves can be buggy, and performance is not likely to matter in this case.
Remember, premature optimization is the root of a lot of spaghetti code.
If you were interested in knowing hard numbers, you could turn your loops into functions and use console.time and console.timeEnd on them. Something like this:
//First while loop
console.time(firstWhileLoopInFunction)
console.timeEnd(firstWhileLoopInFunction)
//Second while loop
console.time(secondWhileLoopInFunction)
console.timeEnd(secondWhileLoopInFunction)
A couple questions:
Is a regular javascript loop (to loop through a series of elements) faster/more efficient than using jQuery each() ??
If so, what is the best way to write the following code as a regular javascript loop?
$('div').each(function(){ //... })
Yes, removing the each() will give you slightly better performance. This is how you could write a for loop for a list of elements.
var divs = $('div');
for(var i = 0; i < divs.length; i++){
var thisDiv = divs[i]; // element
var $thisDiv = $(divs[i]); // jquery object
// do stuff
}
var divs = document.getElementsByTagName('div'),
l = divs.length, i, cur;
for(i=0; i<l; i++) {
cur = divs[i];
// do stuff with cur here
}
Please continue on your path to removing jQuery in the name of efficiency. This code is approximately fifty times faster than the jQuery equivalent.
To answer your second question, due to the first already being answered;
I was also interested in this, and I decided to benchmark the two to find the difference using Gabe's example. The answer is, in circumstances of wanting a jQuery object as the final result:
They perform exactly the same.
http://jsperf.com/jquery-each-vs-native-selectors
Firefox actually finds the jQuery version faster, apparently.
Instead of using jquery .each()
$('div').each(function(){ //... })
You can use document.querySelectorAll(), then convert the HTMLCollection into a JavaScript array. Then you can map over the array of elements.
const elems = document.querySelectorAll('.my-elements')
const $elems = [].slice.call(elems)
$elems.map( (elem) => { console.log(elem) })
I have two tables on my html page with exact same data but there may be few difference which need to be highlighted.
I and using the below Javascript but seems innerHTML does not work as expected-
function CompareTables()
{
var table1 = document.getElementById("table1")
var table2 = document.getElementById("table2")
for(var i=1; i < table1.rows.length; i++)
{
for(var j=1; j < table2.rows.length; j++){
var tab1Val = table1.rows[i].cells[0].innerHTML;
var tab2Val = table2.rows[j].cells[0].innerHTML;
alert(tab1Val.toUpperCase()+"----"+tab2Val.toUpperCase());
var changes =RowExists(table2,tab1Val);
if(!changes[0])
{
table1.rows[i].style.backgroundColor = "red";
instHasChange = true;
}
}
function RowExists(table,columnValue)
{
var hasColumnOrChange = new Array(2);
hasColumnOrChange[0] = false;
for(var i=1; i < table.rows.length; i++)
{
if(table.rows[i].cells[0].innerHTML == columnValue) /*** why these two does not match**/
{
hasColumnOrChange[0] = true;
}
return hasColumnOrChange;
}
}
Please suggest what wrong here.
(table.rows[i].cells[0].innerHTML == columnValue) never returns true even if all values same.
most browsers have bugs with innerHTML and it is not a recommended property to use. different browsers will do different things, usually messing with whitespace, adding/removing quotes, and/or changing the order of attributes.
long story short, never rely on innerHTML.
In it's place, I would recommend using some of the DOM traversal functions, such as .firstChild and .nodeValue. Notice that these are sensitive of white space, and will have to be tweaked if you have anything else in your TD than just text.
http://jsfiddle.net/tdN5L/
if (table.rows[i].cells[0].firstChild.nodeValue === columnValue)
Another option, as pointed out by Micah's solution, is using a library such as jQuery, which will let you ignore most of these browser issues and DOM manipulation pain. I would not recommend bringing in the overhead of jQuery just for this issue, though.
related:
Firefox innerHTML Bug?
innerHTML bug IE8
innerHTML removes attribute quotes in Internet Explorer
Try and use Jquery's method .text
Depending on the browser(Firefox and Chrome's) innerHTML does not work
JQuery takes care of that issue for you.
So lets say I want to hide a div or span with CSS of a particular class.
Is there anyway to do so for the first X number of instances, or better yet, do it for all except for the last one? I imagine this would require javascript.
pseudocode I am thinking would look like this
if divname.class = "XYZ" {
select all instances -1
execute code that inserts random programmatic id into each class
execute code that hides all ids except the last one
}
Am I on the right track? Or is there any easier/better way?
If you can use jQuery and its nice pseudo-selectors, you could do something like
$('.question-summary:not(:last)')
You can test on the SO homepage.
You could do something like this,
var class_div = document.getElementsByClassName("class_name");
var i =0;
for(i=0;i<class_div.length-1;i++){
//do whatever you want with class_div[n-1] elements.
}
I am not sure how you do this with jquery but this is one possible solution for javascript.
If you were using jQuery...
$('.class_name').hide().last().show();
Here ya go - http://jsfiddle.net/uUK6G/
Set all your divs to the same class. Then use jQuery to filter out the last one.
$('.myDiv').filter(':not(:last)').hide();
You can use the :last-child selector in CSS to do this.
http://www.w3schools.com/cssref/sel_last-child.asp
Is there anyway to do so for the first X number of instances, or
better yet, do it for all except for the last one? I imagine this
would require javascript.
You can try:
var elms = document.getElementsByClassName('XYZ'), total = elms.length;
for (var i = 0; i < total; i++){
elms[i].style.display = 'none';
}
In above loop, i will contain index of each element, you can put condition or rather range to specify which ones to delete. For example, if you wanted to hide all except for last one, you would modify it like:
for (var i = 0; i < total - 1; i++){
elms[i].style.display = 'none';
}