Remove&Create VS Search&Update Jquery - javascript

Say I have this HTML mockup.
Say I need to update the information (Value header) in a regular interval, 1s. That should be done for every table in the mockup. I get the data via websocket in JSON format.
The question is: What is the best way to update the data in the tables? Removing the content and creating new DOM elements or searching the DOM elements and updating their values?

Fastest way would be to keep references to DOM elements in js - create each with
tableRefs[row][col]=document.createElement('td');
and keep a reference to it. Then just update through
tableRefs[row][col].innerHTML='yourDataHere';
I wouldn't worry about performance unless you are planning to run on ancient/low performance devices and your data is around 100 rows.

I ended up doing selector accesses via jquery. I updated the HTML mockup because I forgot to mention that I could easily identify the values I have to update by a class selector. I had this class selector before but then simplified the mockup to make a question in here. A performance test is done here. Although this answer doesn't apply to my case is totally valid.
The valid code to update the values is:
$('.values').each(function() {
if ($(this).html() != " ") {
$(this).text("UP1");
}
});
You could also narrow the jquery lookup to specific table (example table from the HTML mockup):
$('#tableWrap_group_1 .values').each(function() {
if ($(this).html() != " ") {
$(this).text("UP1");
}
});

Related

How to avoid Jquery parsing/cleaning up on huge ajax page?

I have a page that requests most of it's content via Ajax. The returned html consists of 2 tables, which I render on the page.
The code I am currently using:
$.post(myUrl, $('form').serialize(), function (data)
{
var $data = $(data);
$('#HeaderIndholdPanel').html($data.find('#GridView1'));
$('#SvarIndholdPanel').html($data.find('#Table1'));
}, 'html');
It does not get any easier, but does it get faster?
The second table is almost 4 MB, so that explains, why it's slow - both tables must be rendered from one request, can't be split.
However I want to optimize it.
I know that Jquery parses the html for scripts and other things. And when the table is replaced it cleans the events assigned to the elements.
Is there any way I can avoid that? It's not neseccary in my case.
I know that my html doesn't have any scripts and I don't assign any avents to it.
Should I return JSON instead and pass that to the native 'innerhtml' method?
Or do you have any better ideas?
I have found that $('#id').replaceWith(data) works much better/faster than $('#id').html(data).
This is because $('#id').html(data) takes the time to trace the object before replacing. When you command a simple replace it seems to ignore any existing value(s) and completes a straight swap.
I found this out when trying to swap out a select list that had thousands or options and using an ajax response to filter it. While watching the code I literally watched it deleted each select option one by one and then re-add it one by one.
Using .replaceWith(data), did a split/quick/1-for-1 replace.
$('#HeaderIndholdPanel').replaceWith($data.find('#GridView1'));
$('#SvarIndholdPanel').replaceWith($data.find('#Table1'));

Query HTML stored in Var with Dojo

I will first explain what I'm trying to do then I will explain why just in case you get bored of reading the whole scenario.
Basically I have some HTML markup stored in a variable I now need to a wait to access the different elements within the variable. For example:
var markUp = "<h3>h3 tag</h3><p>paragraph tag</p>";
What I need to know is if there is a way for me to query the variable to retrieve say the h3 tag, in a similar way you would use the query function ? I have seen some other practices where people append the var to a hidden div then query the div. I would prefer to avoid this but if that is the only way I will proceed.
I have come across this problem whilst developing a drag and drop application, on drop i use a custom creator function to change the items structure once it is dropped.
If further explanation is needed please say, thanks advance Jonathan
You can use dojo._toDom to create a DOM fragment from your string.
var markup = "<h3>h3 tag</h3><p>paragraph tag</p><p>another paragraph</p>";
var domFragment = dojo._toDom(markup);
dojo.query("p", domFragment).forEach(function(element,i) {
console.debug(element.innerHTML);
});
The underscore prefix in _toDom means that it's a "private" member method of dojo. Normally, it's bad practice to use these as if they were public (like I do here). However, in the case of _toDom I believe it's generally considered acceptable, and according to this trac entry, it sounds like it'll be made public in the next version.

Which jQuery operation is faster for 20+ elements?

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")

Jquery and retrieving object via .find()

Via ajax method, I need to fetch an html which is a real mess, half of the elemnts are opened but not closed.
Now I need to find elements which contains time string as in such format: "19:00-20:00" which means it should have something such as "HH:MM-HH:MM".
How can I fetch these rows that contains such time-time elements ?
an example for ajax call source can be found here: http://www.tatlisestv.com/YayinAkisi.asp?Day=3
I am interested with start-end time and the nearest right element that holds the program name for that hour interval.
Regards
$(strong).filter(function() {
return /(\d{2}:\d{2}-?){2}/.test($(this).text());
});
should work (not tested)

What is the most efficient way to access DOM elements in jQuery?

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.

Categories