Differences in speed using document.getElementById(id), $(id), and containerElement.find(id) - javascript

Say I have a container element/div on a page. There are other elements outside of it, comprising page layout/navingation, and there is a fair amount of content inside of it.
In my javascript, I need to find/manipulate a few elements inside of that container. If all of these elements have id properties set, speed wise, is it better to use document.getElementById() (considering that once found, the element will need to be turned into a jQuery object for manipulation) to find them, or to select them using jQuery like so: $("#id"), or to select the container first, store it in a variable, and then select the elements to be manipulated using jQuery like so: container.find("#id")?
Which approach is faster? What does the speed of searches like these depend on?

As jQuery() with an id selector uses document.getElementById inside, using the native method directly is obviously faster. Of course the overhead is neglibible (you never need to select hundreds of elements by id), and they do different things - most likely you want to get a jQuery wrapper object containing the DOM node.
container.find(idselector) is an interesting case, though. As ids are unique all over the document, you should not need such an expression at all. Because of that, id selections are usually boosted by a O(1) lookup table inside the browser, and very fast even for full documents. I'm not sure what happens when you use it inside a container, but it might fall back to a rather slow DOM tree traversal.

Related

How to select all children (any level) and parents of a certain element with jQuery

I have an element #xxx and I have to select all children (any level) and all parent of this element. I dont want to select the element itself.
So far I've been using this jquery code but I am pretty sure there must be a way to make this more efficiently (maybe using addBack):
$("#xxx").find("*").add($("#xxx").parents())
Do you suggest any other alternative that does not make use of add() cause I think this selector is not efficient cause it queries internally again the #xxx. I think using addBack() would be nicer cause it does not cause another search for the element #xxx.
First time answering, please let me know if this is not the right way to do it.
But this is not a direct answer to your original question, but rather to your problem that you mentioned in the comments:
If I remove this selector and replace it with a simpler thing the scroll gets very smooth.
Since you are reusing the selector reference, perhaps you can store the selector, $('#xxx'), as a variable. Since the initial lookup is the heaviest part of the selector.
const $xxx = $('#xxx');
$xxx.find("*").add($xxx.parents())
Performance of jQuery selectors vs local variables

Prefer id attribute or data attribute in page with many elements?

I'm creating a HTML page with many, many "widgets" (can be in the magnitude of 1000, many not visible by display:none which get's modified dynamically by user interaction).
Each widget must carry some information regarding it.
At the moment I'm building that DOM piece by piece and add a jQuery .data() to each widget. But this building of little blocks is too slow (lots of time spent in Parse HTML), so I want to switch to a new approach where I first build a string of all widgets and then add that to the DOM with innerHTML at one go. But this doesn't allow me to use the .data() during the build anymore.
As all widgets have a unique ID anyway (currently only stored in the .data()...) I could think of two obvious solutions:
Give every widget an id attribute with the widget ID as content
Give every widget an data-widgetid attribute with the ID as content
(Parallel to that I'd have a big JavaScript hash that links the widget-id to the per widget data.)
What approach should I prefer?
Performance and resources is an issue (also on mobile devices).
By the id attribute I'm interfering with the DOM, so I don't know if that could have any negative effects. (E.g. it could be that browsers are starting to build an extra look up structure for that internally that I could avoid otherwise. I'm not a browser developer, so I don't know if that is the case though)
Use ID. If you want to protect the ID namespace of the DOM, use a prefix. For example, , where "123" is the unique ID. If your application is driven by a database, the primary key conveniently provides non-colliding ID values. Otherwise use a client-side counter to generate unique IDs.
Accessing the element by ID is much faster via document.getElementById. Modern browsers allow this kind of access really fast. The internal storage is also more efficient comparing to a custom attribute. To access a custom attribute, you'll have to traverse all the matching nodes and compare them with the values of the custom attribute. Some old IE also don't support custom attributes.
If you don't need to get those elements by their id, and you will only use it to associate data with the elements, I would recommend not using id.
Since ids are unique, browsers build a hash table to retrieve elements by id so fast.
Therefore, adding ids to lots of elements that don't need them will increase the size of the hash table unnecessarily.
In average, a search in a hash table is O(1), so the size doesn't matter. However, on the worst case, it's O(n), so better have a small table if you can.
This way, if you use document.getElementById to get other elements, it may be faster.

Storage and retrieval of DOM element

Wondering if anyone out there has ran into this before....
I'd like to use JavaScript to identify a DOM element on a page, then store it's reference in a database or cookie for later retrieval.
To get specific, what I'm looking to do is create a UI so that when the user CLICKs an element on a page, JavaScript fires the click event, passing the instance of the DOM element clicked on.
easy so far, right?
So what I want to do is store the "identity" of this DOM element, say in a database, so when I later return to this page, I can pull out all stored DOM element identities and get access to them in the page once more.
So this is quite simple if this DOM element has a unique ID. Just store the ID, then when the page comes back up, we just do a getElementByID and we've got our DOM element again.
The problem is that not everything in the DOM has a unique identifier, so there the problem lies.
I had some bad ideas initially, like iterating through the entire DOM and incrementing them with unique class names (dom-01, dom-02, etc) and this would give me an identifier. But this would cause a lot of initial overhead and if the page ever changed, the order of the DOM elements wouldn't be the same, so we wouldn't get back the correct DOM elemet.
I'mve never tried it, but another thought was to serialize the DOM element, stick it in the DB, and then on reload parse to an object, and use that object to find my original DOM element. I've never done that before, so how I can actually compare the restored (parsed) object to the one in the DOM is a big unknown.
Specifics on the serialization solution or any other original ideas for accomplishing this are welcome!!
Thanks in advance everyone!
Here's a jsFiddle solution attempt: http://jsfiddle.net/techbubble/pJgyu/7720/
The approach I took was to compute a simple hash of the HTML content of the target element, or if no such content is present, a hash of the aggregated attributes and values of the element. I have a getElementHash() function that returns a string in the format: TAG:[H | A]:Hash (the H or A indicates if the HTML content or attributes were used to calculate the hash). This produces a unique key for any element on the page that either has HTML content or has at least one attribute (miniscule risk of duplication possible).
For retrieving an element with a previously saved key, I created a getElementByHash() function. It uses the tag that is extracted from the key in a jQuery selector. For each element returned, the HTML content or attributes hash is computed (based on the value "H" or "A" specified in the key) to see if it matches the hash in the key. If there is a match, the search ends and the element is returned.
This approach is impervious to the element being moved around on the page as long as its HTML content (or attributes) remain unchanged. It does not produce a key for elements that have neither any HTML content nor any attributes (which makes them pretty useless anyway).
If you want to keep the location of the node in the DOM, why not just keep an XPath of it? XPath allows you to keep an exact location of a node in a document, as long as that location doesn't change. For instance, you can say something like
//div[#id="xpath_is"]/span[class="cool"]/a[4]
Meaning the 4th <a> tag within a <span class="cool"> within a <div id="xpath_is">
http://www.w3.org/TR/xpath/
http://www.w3schools.com/xpath/default.asp
You can get the XPath of an attribute by Inspecting it with Firebug and right clicking on the node and selecting "Copy XPath". I'm not sure how easy it is to get it from a DOM Node (there are ways, but not sure how many baked implementations there are lying around). It'd be relatively easy to simply look for an ancestor (by traversing upward with .parentNode and building one) and adding .classNames and .ids as you go - but I'm too lazy to write this right now, ;).

Faster to manipulate existing HTML or removing the HTML and then recreating it?

This project I am working on, I have a list of elements and convert them into a "graph" (not a true graph, but you can call it a psuedo one). I have my data set, i run a for loop over the data and then create a li element for each one, create and parent ul, append the lis and then append the parent to another DOM element (we'll call it grandparent) already on the page. After that, i have to make subsequent updates to that list based on user interaction.
Also, this is all in the context of using jQuery.
Now, my question is - is it faster to create the elements once then update the resulting HTML on each subsequent call or is it faster to just recreate each element, empty() the grandparent element (which would get rid of the parent ul) and then reappend the newly created ul (which I am doing now)?
Keep in mind that when I am recreating the lis, they are not in the DOM at all so there is no repaint/reflow while recreating them. The repaint only happens when I reappend the newly created ul.
I was speaking to a coworker and he said it would be better to just update the HTML elements once they are created rather than recreating them every single time. i was thinking of going this route, but then I thought that updating the existing lis would actually cause a repaint on say 50 elements versus just doing one massive one with the empty() then reappending the newly created ul.
thoughts?
As rsp says, you'll need to profile your solutions, as which will be fastest depends both on the structure of your markup and on the particular browser its running on. It's also, of course, only worth going through all this effort if you're unhappy with the speed you're currently getting!
There are three basic approaches, however, each of which could be the fastest. The first only causes a single repaint; the others only two, if you choose your parent node well.
Construct your new content as HTML strings ([...].join("")), then apply with .html(). Pros: typically faster than method #2. Cons: not necessarily by much, can leave stale jQuery data/events (i.e. can leak, if you aren't careful).
Construct your new content with jQuery outside the document (e.g. put all your <li>s into a <ul>, then insert the <ul> into the document after construction is complete), then insert normall. Pros: tends to be easier to read than method #1. Cons: performs worse the more complex your markup gets.
Remove the existing nodes from the document (ideally, a single parent node, like the <ul>), make your changes, then reinsert them. Pros: may be clearer and more performant than method #2, especially on complex markup. Cons: becomes much more complex if the number of elements changes between renderings.
The last one only causes two repaints even though you're making a large number of changes, because only the initial removal and final insert affect the document. Changing elements outside the document doesn't cause repaints.
I would suggest profiling your code first. Premature optimization is the root of all evil.

using hidden elements in pages to store data

I need to store data in html documents that are associated with elements, and that I can get to with javascript. I think I want to avoid arbitrary attributes on elements, since after reading various posts here I don't trust them. I can't use id or class, since I those are used for other things and I don't want to mess with them (my project has to work on wide varieties of html so I can't make any assumptions as to the design of the class and id structure). Another thing I need is for whatever I do, it needs to survive round-tripping through innerHTML (of a parent or ancestor element of the element I need to tag with data), with data intact.
I have considered various hidden elements (including script tags and html comments), which I insert into the document right before the element I need to tag with data. Currently my favorite is hidden form elements (i.e. input with type "hidden"). I can stick any data I want into the "value" of the element, and I can find all such elements easily enough with getElementsByTagName(). Also importantly, it doesn't seem to affect the layout of the page.
I'm curious about the ramifications of this, and if anyone can think of any any problems with it. I need to be able to put them anywhere in body of the page, before any element. For instance I might need them associated with an option element (a child of a select element), so that rules out using a hidden div, since putting one of those inside a select element is illegal. I don't think they will affect form behavior, since they don't have a name attribute (I can avoid using id's if that helps).
Any thoughts on this, or suggestions for other ways of accomplishing the same that meets my needs?
If this is going to be data for JavaScript's purposes, why even try to put it in the HTML at all? Here's a simple example of what I mean
<script type="text/javascript">
var nodeData = {
foo: {/* Data to associate with div#foo */}
, bar: {/* Data to associate with div#bar */}
};
</script>
<div id="foo">Foo!</div>
<div id="bar">Bar!</div>
It's simple and elegant since the principle of IDs being unique per document nicely matches with javascript's dictionaries requiring unique keys per entry.

Categories