I would like to know what is more appropriate to do if I really need a good performance for my app. I'm programming cross-platform apps via PhoneGap and the way I code is very crucial.
Which is more appropriate:
document.getElementbyID('id').addEventListener()
or
var id = document.getElementbyID('id');
id.addEventListener();
and how can I use the keyword "delete" to improve the performance of my app?
According to this test i just made on jsperf.com, document.getElementbyID('id').addEventListener() seems to be the fastest way. - in Chrome on Mac OS X.
Try it on the desired browsers, and edit the test to add/remove features such as the delete you were talking about.
The difference between the two will be marginal. To improve performance you should minimize the number of event handlers you add to the dom and remove those you don't require again. Delete doesn't make sense in the context you posted. It should be used to free up items in (associative) arrays or to remove objects you created. You do neither of those in your example.
For lists in which each item is clickable you should just attach one event handler to the list container and not to individual elements. You can then use the target property of the event object passed into the handler to find the actual listitem that was tapped.
edit: an example on how to use one event handler for multiple list items
The li.id is used to identify the actual item that was clicked. If the 'li' have children you might have to walk up the target DOM tree until you find the correct item.
<ul id="list">
<li id="item_1">First Item</li>
<li id="item_2">Second Item</li>
<li id="item_3">Third Item</li>
<li id="item_4">Fourth Item</li>
<li id="item_5">Fifth Item</li>
<li id="item_6">Sixth Item</li>
<li id="item_7">Seventh Item</li>
</ul>
<script>
window.onload(function() {
document.getElementById("list").addEventListener("click",
function(event) { alert("" + event.target.id + " was clicked"); });
});
</script>
JavaScript is interpreted at runtime, so ultimately it depends on whether or not the compiler optimizes away that variable allocation or not. Either way, the difference will be extremely small. Build a few tests and see.
Focus on readability (and finding a model where you are not worried about micro-optimization).
and how can i use the keyword "delete" to improve the performance of
my app?
Since you are discussing performance-intensive applications, I assume you are interested in proper garbage collection in JavaScript. See How does garbage collection work in JavaScript?
It is better to use
var id = document.getElementbyID('id');
id.addEventListener();
If you require the DOM element more than once else it takes same time for both ways.
Related
I have an unordered list, where I am using an ID to identify the current list item that was last clicked. On click of a different item, I am using js to switch the id to a different item in the list, so that styling could be applied.
It seems intuitive to me that a unique item that can only be used once (a selected li item) should be identified as an ID, and that is why I did that, but I was told it is bad practice to do so.
I wouldn't do so. This rather seems an opportunity for you to discover HTML 5's data attribute, which you can use for both CSS styling (using attribute selector) and JS use (with dataset or jQuery's .data() method).
Quick definition from MDN :
HTML5 is designed with extensibility in mind for data that should be
associated with a particular element but need not have any defined
meaning. data-* attributes allow us to store extra information on
standard, semantic HTML elements without other hacks such as
classList, non-standard attributes, extra properties on DOM, or
setUserData.
In HTML side :
<!-- You can use data without value, and just test its presence -->
<li data-selected>
...
</li>
In CSS :
li[data-selected]{
...
}
Your question actually has a couple of interesting components, let me try to answer them as good as I can :-)
"Is it an ok practice to change an ID using javascript if the element is unique?"
You could say it's a justifiable case, if the element really is unique, then there's no real harm in "moving" the ID with JavaScript.
BUT
In your description you touch on something more fundamental:
"On click of a different item, I am using js to switch the id to a different item in the list, so that styling could be applied."
If this is the case (you change the ID for styling), then I'd recommend using a class instead. People previously already gave you a good hint, something like an "is-active" class would be very useful as it's less specfic than an ID, can be used on multiple items if needed and if you use classes that determine a state (like "is-active", "has-children", "is-animating", etc.), it's really easy to re-use them in later parts of code as well and it is clear what the element is doing at the moment.
A little code for reference:
HTML
<ul>
<li>Some item</li>
<li class="is-active">Some item</li>
<li>Some item</li>
<li>Some item</li>
</ul>
CSS
.is-active {
color: #eee;
background-color: #222;
}
jQuery
// You probably want a bit more specific selector, but it's just an example.
$('li').on('click', function() {
var $element = $(this),
$elements = $('li');
if (!$element.hasClass('is-active')) {
$elements.removeClass('is-active');
$element.addClass('is-active');
}
});
Since you might need to reference the specific id of an element at some future point, changing it is probably a bad idea. In your case it would be better to just apply a class to the last item clicked.
Rather than use $('.list').find('li:not(.done):last'), which returns all LI that is not .done and is the last of every .list, how can I use functions instead?
For instance, $('.list').find('li').not('.done').last() would return just one item, because it searches all .list for LI that aren't .done and then just returns the last one.
There are a few reasons I want to do this. Primarily, typically using functions are faster than CSS selectors (in some cases, especially when you split them up into multiple functions as jQuery doesn't have to manually split up the selectors, and oftentimes jQuery functions are just mapped directly to existing CSS selectors anyway). But anyway, curiosity is my main reason at the moment, and performance is secondary.
Sample code (not entirely representative of the actual code, but the structure is similar):
<ul class="list">
<li>One</li>
<li class="done">Two</li>
</ul>
<ul class="list">
<li class="done">Three</li>
<li>Four</li>
</ul>
I want to return the nodes for:
One and Four.
I'm not coming up with a way to do it that doesn't require looping, e.g.:
$(".list").map(function() {
var items = $(this).find("li").not(".done");
return items[items.length - 1];
});
// Old way
$(".list").find("li:not(.done):last").css("color", "red");
// Just to show it's wrong (as the question says)
$(".list").find("li").not(".done").last().css("background-color", "yellow");
// Alternative
$(".list").map(function() {
var items = $(this).find("li").not(".done");
return items[items.length - 1];
}).css("border", "1px solid black");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="list">
<li>One</li>
<li>Two</li>
<li class="done">Three (done)</li>
</ul>
<ul class="list">
<li>One</li>
<li>Two</li>
<li class="done">Three (done)</li>
</ul>
The reason you might think using selectors is slower is that selectors like :last are jQuery extensions, not true CSS selectors, meaning that Sizzle (jQuery's selector engine) has to process them in JavaScript, rather than offloading them to the (much faster) selector engine built into the browser. If you restrict yourself to CSS selectors the browser implements, typically the selector will win (modulo other factors, and YMMV). I can't account for your seeming to see the DOM being changed by :not(.done) (which is a valid CSS selector), unless Sizzle does something It Really Shouldn't to process that (since Sizzle supports complex selectors within :not whereas CSS doesn't).
You don't actually need a function. Any of the following selectors would return the nodes for One and Four:
$('.list li:not(.done)')
$('.list li').not('.done')
$('li:not(.done)')
Using $('.list li:last-child').not('.done') would return those items that are both the last child and don't have a done class (Four).
That said, if you really want to use a function, you could go with jQuery's .contents() and .filter() methods.
$('.list').contents().filter( function(i,v){
if( v.nodeType === 1 && !$(v).hasClass('done') ){
return v; // Returns 'One' and 'Four'
}
});
Here's a fiddle of all of the above.
There are a few reasons I want to do this. Primarily, typically using functions are faster than CSS selectors
There are LIs that I don't want, and I want the last of every list that doesn't match a class
The fastest method would be XPath, since it is native:
//*[#class='list']/li[#class!='done']/*[last()]
But anyway, curiosity is my main reason at the moment, and performance is secondary.
jQuery 1.0 supported XPath, then switched to the selector engine which eventually became Sizzle:
Lately, I’ve been doing a lot of work building a parser for both XPath and CSS 3 – and I was amazed at just how similar they are, in some respects – but wholly different in others. For example, CSS is completely tuned to be used with HTML, with the use of #id (to get something by ID) and .class (to get something by its class). On the other hand, XPath has to ability to traverse back up the DOM tree with .. and test for existence with foo[bar] (foo has a bar element child). The biggest thing to realize is that CSS Selectors are, typically, very short – but woefully underpowered, when compared to XPath.
which were removed in 1.2:
Since XPath selectors were removed form jQuery in 1.2, a new XPath Selector Plugin has been introduced. You can use this plugin to give yourself the CSS/XPath hybrid selectors that have existed in jQuery since its creation.
DOM traversal techniques include:
Tree Walker
An implementation using the DOM Level 2 Tree Walker methods. Builds a generic filter function and traverses through all elements.
XPath
Building a single expression and letting the XPath engine traverse through the document, finding all the relevant elements.
Hybrid
Mixes an XPath and DOM implementation; using XPath wherever possible.
References
John Resig - XPath and CSS Selectors
John Resig - getElementsByClassName Speed Comparison
jQuery 1.2 Release Notes
jQuery XPath Plugin
Having a HTML/css/Javascript based menu system.
The menus themselves are dynamically built using Javascript and ends up in something like this:
<ul>
<li><span class="icon icon-star"> </span></li>
<li><span class="icon icon-boat"> </span></li>
<li><span class="icon icon-bike"> </span></li>
</ul>
I also plan to have a serverside version (build the menus using server script) and / or static versions. Have to do some benchmarks when it is all up and running.
The span holds icons by sprite background.
Now, instead of adding event listener to each menu entry I add one to the UL and on klick or key-down I locate the selected menu entry from the event. Typically:
a = event.target;
// Find the LI element.
for (li = a; li && li.nodeName != "LI"; li = li.parentNode)
;
// Find the anchor (Typically if the span was clicked).
if (a.nodeName !== 'A')
for (; a && a.nodeName != "A"; a = a.parentNode)
;
This works fine but the question becomes how to identify which action should be taken – as in which menu entry was clicked.
Would it be OK to use the data- tag?
Typically something like:
<a href="#" data-menu="1">...
And then use a switch routine to determine menu entry.
My initial thought was to use ID's, but as I see it using the data- attribute is more flexible and less prone for clashes and complications.
Initially the idea behind attaching only one event listener per menu is to lessen the load at page load and instead do the finding when menu entry are clicked as by then in most cases that can take precedence when it comes to resource usage. I also need to style the LI element by adding/removing a .menu_selected class upon menu selection.
I'm a bit unsure about the design as a whole. It works fine by the (few) test I have done, but there might be some caveats I'm not seeing.
This is targeting never browsers only. HTML5 + canvas.
… and now I'm unsure how good a question this is, but I'll give it a try and delete if not appropriate.
Would it be OK to use the data- tag?
Certainly, you can delegate events on any selector.
The jQuery library makes this much easier too:
$('ul').on('click', '[data-menu]', function () {
...do awesome stuff...
});
The code above binds a click handler to any and all <ul> elements, and fires off event callbacks on any element clicked within the <ul> elements that matches the '[data-menu]' selection.
I don't recommend adding jQuery for the sake of adding jQuery, but jQuery is very useful for managing delegated events. If you're able to take the minor performance hit of downloading an additional library, then it'll make writing code significantly easier.
Probably this will not result in any noticable performance difference, but I was just interested. If I am removing a class on a list of elements using jQuery, is it better practice or performance to include the class in the selector?
So either include it:
$('#myList li.classToRemove').removeClass('classToRemove');
or don't include it:
$('#myList li').removeClass('classToRemove');
So basically is there any difference to narrowing the list in the selector and in the removeClass method.
Selectors are matched backwards (last to first), meaning it will first find "all elements with "classToRemove" which are also "li" which are also children of "#mylist" ".
It's done that way to narrow down the list as much as possible, as soon as possible.
Therefore, you should go with
$('#myList li.classToRemove').removeClass('classToRemove');
Less items to match means a faster, more efficient script.
Assuming that not all the <li> elements have that class, then I'd say that it's better to run .removeClass() on the filtered set.
But overall, there will be other things that will have an impact on the performance, like...
The number of elements matched by '#myList li' vs '#myList li.classToRemove'
The way different environments optimize their DOM selection
The actual performance difference of the innards of the .removeClass() method between different environments
So unless you're talking about unnecessarily running .removeClass() on a large subset of elements, I wouldn't worry about it too much.
Using the more specific selector will improve performance but it won't affect the result of .removeClass().
Think of each addition to a selector like a drill down. Given the html below:
<div id="myList">
<ul>
<li id="li1"></li>
<li id="li2"></li>
<li id="li3" class="classToRemove"></li>
</ul>
</div>
//In order of fastest to slowest:
//Selecting the exact li and calling removeClass once
$('#li3').removeClass('classToRemove');
//In this one we are skipping 2 li's and then calling removeClass once
$('#myList li.classToRemove').removeClass('classToRemove');
//In this one we have to call removeClass 3 times
$('#myList li').removeClass('classToRemove');
Sorry to bump an old post.
The test at this page seems to suggest that NOT including the class selector is around 10-15% quicker. So, if you want to use jQuery, the best approach is just:
$('#myList li').removeClass('classToRemove');
Note - this page does appear to use jQuery 1...
Background
I have been using Backbone.js for some time and one aspect of it that impresses me is how it allows me to simplify, abstract and reuse DOM elements as 'views'. I have tried to read through some of the annotated source and am familiar with JQuery, but have little knowledge of how the DOM works on a deeper level.
Question
How does Backbone.JS tie DOM elements to views without assigning an id, class or other attribute to them?
i.e.
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
</ul>
I love that Backbone does this and would like to know how it does it!
In javascript, a variable can hold a reference (i.e a programmatic thing that "refers to") to some element of the DOM, which is just a Javascript object. Backbone makes sure that for a view, at least that element exists. For example, in jQuery, when you refer to the third item in your list:
var item3 = $('ul li').eq(2);
(It's a zero-offset list, the first item is at index 0, the third at index 2), you can now change the text from "Item three" to "Item three point one four one five nine" with ordinary jQuery DOM manipulators:
item3.text("Item three point one four one five nine");
Even though that list item doesn't have any particular class or ID attributes.
A backbone view's el field contains a constant reference to the parent element in which that view renders all of its stuff. Backbone uses the jQuery delegate event manager to attach a generic event handler to that one constant reference. Whenever an event happens within that DOM element or any of its children, the delegate catches the event, along with a reference to the specific DOM object within the parent el that created the event, and backbone uses some fairly standard jQuery magic to map that to an event handler in the view.
It is, indeed, very cool stuff.
I should add that the "constant"-ness of the el reference is, er, arguable. If you're attaching view logic to an existing HTML element, you do assign to the el once, in the view's initialize(). Javascript doesn't enforce any notion of constantness, but you should only directly assign to el (ie this.el = something()) if you're sure you know what you're doing.