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")
Related
I need to parse many string values (which are probably HTML) to HTML and then, get it own height (as HTML node). I don't want to create real node inside my real HTML, probably there is a way to create fake one and get it height?
Example:
const arrOfHtml = ["<div>Test</div>", "<div><h2>Test2></h2></div><div><p>Im not ok</p></div>"];
arrOfHtml.forEach(el => {
console.log($(el).height())
})
Pointy makes a great point in their comment.
If you want to get the height of an HTML node, you have to render it. You don't really have a choice, elements have to be added to the DOM. I've found that performance isn't usually an issue unless you have hundreds of elements.
I have a html code like
<div>
<span>TV</span>
</div>
I want to find this span through documentObject having text 'TV', like getElementById etc ... something like getElementByText. I know that it's possible through XPath/JQuery/Regex.
But I need it to get through DOM object model only. As only DOM model is available in my context.
I see couple of answers:
Finding an html element ID based on a text displayed
jquery - find element that only has text and not any other html tag
how to find element after some text with javascript?
But these are not helpful to me, as I need to get it through DOM model only.
Assuming the document is well-formed enough to parse into a proper DOM object tree, you can iterate through the entire structure without using an external library. Depending on the structure, you may have to examine every node to find all matches, and this may be slow. If you have access to IDs of any sort, you may be able to reduce search scope and improve performance.
The key property you will need is the childNodes collection on every DOM node. Starting with the BODY (or some other container), you can recurse through all the child nodes.
This site is pretty basic but shows dependency-free methods for accessing DOM elements. See the section called "Tools to Navigate to a Certain Element".
I noticed that you mentioned regular expressions as a means to find elements. Regexes are poor for parsing entire documents, but they can be very useful in evaluating the textual content of a single node (e.g. partial matches, pattern matches, case insensitivity, etc.) Regular expressions are part of the JavaScript language itself and have been so for well over a decade.
Only thing I can think of is something like this:
function getElementByTextContent(text)
{
var spanList = document.getElementsByTagName("span");
for (var i = 0, len = spanList.length; i < len; i++)
{
if(spanList[i].textContent === text) // use .innerHTML if you need IE compatibility
return spanList[i]
}
}
of course it assumes you are only searching for <span> elements, but this might work for you. Here's a demo as well:
http://jsfiddle.net/uATdG/
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'));
I am trying to increase the jquery performance of my mobile html 5 app. I read some guides about storing used jquery selectors in global objects. The app is pretty big and I didn't expected a big perfomrance boost, but the app was running even slower (like 20%).
I only use jquery to find elements by Id ( $("#id") or $_element.find("#id")). Ids are unique, so I am only interested in finding the first element. I managed to globalize all jquery calls in a cacheHandler object, which stores all selectors by id. The cache is cleared frequently and contains around 30 elements per cycle.
With this changes the app ran slower, so I tried some more things to increase performance:
cache[id] = $(document.getElementById("id"))
cache[id] = document.getElementById("id")
store selectors with hashCode: cache[id.hashCode()]
I came up with the idea, that this solution is slow, because the memory is increased frequently, because the whole dom with all its children is stored in the cache.
So I had the new Idea, to cache the element path as array, like
document.body.children[1].children[5].children[0] => [1,5,0]
So I just have to find the element once, store the array and look up the path, if I need the element again.
This doesn't change anything, and all ideas were even slower than calling $("#id"), whenever I need the element.
If needed I can provide more informations or snippets.
I am thankfull for each explanation, why this is slowing down my app.
If it's a mobile html5 app why are you using jQuery for selectors? Seems very redundant.
I usually do somthing along the lines of this:
// helpers, since i hate typing document.get ..
function _id(e){ return document.getElementById(e); } // single id
function _all(e){ return document.querySelectorAll(e); } // single elem
function _get(e){ return document.querySelector(e); } // multiple elem
// loop helper (for changing or doing things to collection of elements)
function _for(e,f) { var i, len=e.length; for(i=0,l=len;i<l;i++){ f(e[i]); }}
// VARs (global)
var c = _id('c'), // main selector
box = c.querySelectorAll('.box'), // boxes in 'c'
elements = box.querySelectorAll('.element'); // elems in 'box'
// Change background-color for all .box using the _for -helper
_for(elements, function(e){ e.style.backgroundColor = 'red'; }
I only store main parents of elements so that i can then query down the DOM if needed (limiting the lockup needed for traversing). In the example variables above one could imagine that something in the .box would change several times OR that .box is a slow selector.
Do note that global variables increase memory usage though since those variables can interfer with garbage collection. Also note that objects can be slower in some browsers and if it doesn't bloat your code to much you should instead store it more plainly (you shouldn't store too many global variables anyway so....).
Edit, jsPerf:
http://jsperf.com/global-vs-local-vars-14mar2015
Do note however that depending on what you're selection and exactly what you're doing will have the greatest impact. In the jsPerf-example the difference between local and global quickly diminishes as soon as one starts selecting descendants from the globally cached selectors ie doing box.find('p').css('color','blue') etc.
This is quite old but we never know, someone can read this post.
jQuery is based on Sizzle which is way smaller: https://sizzlejs.com/
You can eventually include only this library. I would not recommend to maintain your own piece of code for this purpose. It is already done and maintained by someone else.
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.