I'm sorry if this is a novice question, but I'm not very knowledgeable when it comes to Javascript...
So, here's the code snippet:
function insertSquares() {
for (i = 0; i < 113; i++) {
$('#wrapper').append('<span><img src="images/square_2.png" style='display: none;'/></span>');
}
}
As you can see, I have a loop that appends a <span> and an <img> to a <div> each time that the code is repeated. Normally, this appending isn't a problem, but since it has to do this a number of times in the loop, so it takes a while. (also, this function is called a number of times by a setInterval(), and it slows down the entire webpage)
When benchmarking this function with JSLitmus, it runs 5 ops/sec, and I would like to speed this up. I have already thought of using the loop to add the data to an array instead, (rather than appending each time through the loop) and then when outside of the loop, appending all of the data only once, but this does not seem to speed up the process by a noticeable amount.
So, is there some way I can speed this code up that I haven't thought of? I can't think of a more efficient way to load and display this amount of the same image.
The best thing you can do is wait until you've finished the loop to make your changes to the DOM. Your current method will hammer the DOM into submission, and you certainly don't want this. Consider Document Fragments instead.
John Resig wrote about DOM Document Fragments some time back, but the post is still a good primer. You can find it online at http://ejohn.org/blog/dom-documentfragments/.
You could just work with strings until you need to append it.
function insertSquares() {
var html = '';
for (var i = 0; i < 113; i++) {
html += '<span><img src="images/square_2.png" style="display: none;"/></span>';
}
$('#wrapper').html(html);
}
For smooth performance I agree with #jonathon-sampson and #timrwood that one modification to the DOM is preferable to many.
That said, the other way to boost your performance is to minimize the amount of html you are inserting into the DOM. In your case I'd try to cut each element down to a single <span> block if possible using a CSS class to encapsulate common stylistic elements.
from:
html += '<span><img src="images/square_2.png" style="display: none;"/></span>';
to:
html += '<span class='myclass'></span>';
As a comment above noted, if you can avoid all of this in general and handle the creation of the DOM server side, that really would be the 'best' solution.
Related
as the question suggests the page animations become choppy the more DOM i insert in the page dynamically through Javascript. I don't know what is causing the problem or if this is a "normal" behaviour. I might have a memory leak somewhere or some bad code performance.
Thanks
Edit: some code as requested
var somevariable = 40;
var html = [];
for(i = 0; i<somevariable;i++){
html.push('20 elements');
}
$("#data-positioner").append(html);
The animation that is done later on is not for these inserted elements but for other elements.
This process is repeated on a click event.
In tutorials I've learnt to use document.write. Now I understand that by many this is frowned upon. I've tried print(), but then it literally sends it to the printer.
So what are alternatives I should use, and why shouldn't I use document.write? Both w3schools and MDN use document.write.
The reason that your HTML is replaced is because of an evil JavaScript function: document.write().
It is most definitely "bad form." It only works with webpages if you use it on the page load; and if you use it during runtime, it will replace your entire document with the input. And if you're applying it as strict XHTML structure it's not even valid code.
the problem:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-- quote from the MDN
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading, the document is "open". When the document has finished loading, the document has "closed". Using document.write() at this point will erase your entire (closed) HTML document and replace it with a new (open) document. This means your webpage has erased itself and started writing a new page - from scratch.
I believe document.write() causes the browser to have a performance decrease as well (correct me if I am wrong).
an example:
This example writes output to the HTML document after the page has loaded. Watch document.write()'s evil powers clear the entire document when you press the "exterminate" button:
I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!
the alternatives:
.innerHTML This is a wonderful alternative, but this attribute has to be attached to the element where you want to put the text.
Example: document.getElementById('output1').innerHTML = 'Some text!';
.createTextNode() is the alternative recommended by the W3C.
Example: var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
NOTE: This is known to have some performance decreases (slower than .innerHTML). I recommend using .innerHTML instead.
the example with the .innerHTML alternative:
I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
me!
<p id="output1"></p>
Here is code that should replace document.write in-place:
document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
}
You can combine insertAdjacentHTML method and document.currentScript property.
The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position:
'beforebegin': Before the element itself.
'afterbegin': Just inside the element, before its first child.
'beforeend': Just inside the element, after its last child.
'afterend': After the element itself.
The document.currentScript property returns the <script> element whose script is currently being processed. Best position will be beforebegin — new HTML will be inserted before <script> itself. To match document.write's native behavior, one would position the text afterend, but then the nodes from consecutive calls to the function aren't placed in the same order as you called them (like document.write does), but in reverse. The order in which your HTML appears is probably more important than where they're place relative to the <script> tag, hence the use of beforebegin.
document.currentScript.insertAdjacentHTML(
'beforebegin',
'This is a document.write alternative'
)
As a recommended alternative to document.write you could use DOM manipulation to directly query and add node elements to the DOM.
Just dropping a note here to say that, although using document.write is highly frowned upon due to performance concerns (synchronous DOM injection and evaluation), there is also no actual 1:1 alternative if you are using document.write to inject script tags on demand.
There are a lot of great ways to avoid having to do this (e.g. script loaders like RequireJS that manage your dependency chains) but they are more invasive and so are best used throughout the site/application.
I fail to see the problem with document.write. If you are using it before the onload event fires, as you presumably are, to build elements from structured data for instance, it is the appropriate tool to use. There is no performance advantage to using insertAdjacentHTML or explicitly adding nodes to the DOM after it has been built. I just tested it three different ways with an old script I once used to schedule incoming modem calls for a 24/7 service on a bank of 4 modems.
By the time it is finished this script creates over 3000 DOM nodes, mostly table cells. On a 7 year old PC running Firefox on Vista, this little exercise takes less than 2 seconds using document.write from a local 12kb source file and three 1px GIFs which are re-used about 2000 times. The page just pops into existence fully formed, ready to handle events.
Using insertAdjacentHTML is not a direct substitute as the browser closes tags which the script requires remain open, and takes twice as long to ultimately create a mangled page. Writing all the pieces to a string and then passing it to insertAdjacentHTML takes even longer, but at least you get the page as designed. Other options (like manually re-building the DOM one node at a time) are so ridiculous that I'm not even going there.
Sometimes document.write is the thing to use. The fact that it is one of the oldest methods in JavaScript is not a point against it, but a point in its favor - it is highly optimized code which does exactly what it was intended to do and has been doing since its inception.
It's nice to know that there are alternative post-load methods available, but it must be understood that these are intended for a different purpose entirely; namely modifying the DOM after it has been created and memory allocated to it. It is inherently more resource-intensive to use these methods if your script is intended to write the HTML from which the browser creates the DOM in the first place.
Just write it and let the browser and interpreter do the work. That's what they are there for.
PS: I just tested using an onload param in the body tag and even at this point the document is still open and document.write() functions as intended. Also, there is no perceivable performance difference between the various methods in the latest version of Firefox. Of course there is a ton of caching probably going on somewhere in the hardware/software stack, but that's the point really - let the machine do the work. It may make a difference on a cheap smartphone though. Cheers!
The question depends on what you are actually trying to do.
Usually, instead of doing document.write you can use someElement.innerHTML or better, document.createElement with an someElement.appendChild.
You can also consider using a library like jQuery and using the modification functions in there: http://api.jquery.com/category/manipulation/
This is probably the most correct, direct replacement: insertAdjacentHTML.
Try to use getElementById() or getElementsByName() to access a specific element and then to use innerHTML property:
<html>
<body>
<div id="myDiv1"></div>
<div id="myDiv2"></div>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
myDiv2.innerHTML = "<i>Content of second DIV element</i>";
</script>
</html>
Use
var documentwrite =(value, method="", display="")=>{
switch(display) {
case "block":
var x = document.createElement("p");
break;
case "inline":
var x = document.createElement("span");
break;
default:
var x = document.createElement("p");
}
var t = document.createTextNode(value);
x.appendChild(t);
if(method==""){
document.body.appendChild(x);
}
else{
document.querySelector(method).appendChild(x);
}
}
and call the function based on your requirement as below
documentwrite("My sample text"); //print value inside body
documentwrite("My sample text inside id", "#demoid", "block"); // print value inside id and display block
documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline
I'm not sure if this will work exactly, but I thought of
var docwrite = function(doc) {
document.write(doc);
};
This solved the problem with the error messages for me.
In tutorials I've learnt to use document.write. Now I understand that by many this is frowned upon. I've tried print(), but then it literally sends it to the printer.
So what are alternatives I should use, and why shouldn't I use document.write? Both w3schools and MDN use document.write.
The reason that your HTML is replaced is because of an evil JavaScript function: document.write().
It is most definitely "bad form." It only works with webpages if you use it on the page load; and if you use it during runtime, it will replace your entire document with the input. And if you're applying it as strict XHTML structure it's not even valid code.
the problem:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-- quote from the MDN
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading, the document is "open". When the document has finished loading, the document has "closed". Using document.write() at this point will erase your entire (closed) HTML document and replace it with a new (open) document. This means your webpage has erased itself and started writing a new page - from scratch.
I believe document.write() causes the browser to have a performance decrease as well (correct me if I am wrong).
an example:
This example writes output to the HTML document after the page has loaded. Watch document.write()'s evil powers clear the entire document when you press the "exterminate" button:
I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!
the alternatives:
.innerHTML This is a wonderful alternative, but this attribute has to be attached to the element where you want to put the text.
Example: document.getElementById('output1').innerHTML = 'Some text!';
.createTextNode() is the alternative recommended by the W3C.
Example: var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
NOTE: This is known to have some performance decreases (slower than .innerHTML). I recommend using .innerHTML instead.
the example with the .innerHTML alternative:
I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
me!
<p id="output1"></p>
Here is code that should replace document.write in-place:
document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
}
You can combine insertAdjacentHTML method and document.currentScript property.
The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position:
'beforebegin': Before the element itself.
'afterbegin': Just inside the element, before its first child.
'beforeend': Just inside the element, after its last child.
'afterend': After the element itself.
The document.currentScript property returns the <script> element whose script is currently being processed. Best position will be beforebegin — new HTML will be inserted before <script> itself. To match document.write's native behavior, one would position the text afterend, but then the nodes from consecutive calls to the function aren't placed in the same order as you called them (like document.write does), but in reverse. The order in which your HTML appears is probably more important than where they're place relative to the <script> tag, hence the use of beforebegin.
document.currentScript.insertAdjacentHTML(
'beforebegin',
'This is a document.write alternative'
)
As a recommended alternative to document.write you could use DOM manipulation to directly query and add node elements to the DOM.
Just dropping a note here to say that, although using document.write is highly frowned upon due to performance concerns (synchronous DOM injection and evaluation), there is also no actual 1:1 alternative if you are using document.write to inject script tags on demand.
There are a lot of great ways to avoid having to do this (e.g. script loaders like RequireJS that manage your dependency chains) but they are more invasive and so are best used throughout the site/application.
I fail to see the problem with document.write. If you are using it before the onload event fires, as you presumably are, to build elements from structured data for instance, it is the appropriate tool to use. There is no performance advantage to using insertAdjacentHTML or explicitly adding nodes to the DOM after it has been built. I just tested it three different ways with an old script I once used to schedule incoming modem calls for a 24/7 service on a bank of 4 modems.
By the time it is finished this script creates over 3000 DOM nodes, mostly table cells. On a 7 year old PC running Firefox on Vista, this little exercise takes less than 2 seconds using document.write from a local 12kb source file and three 1px GIFs which are re-used about 2000 times. The page just pops into existence fully formed, ready to handle events.
Using insertAdjacentHTML is not a direct substitute as the browser closes tags which the script requires remain open, and takes twice as long to ultimately create a mangled page. Writing all the pieces to a string and then passing it to insertAdjacentHTML takes even longer, but at least you get the page as designed. Other options (like manually re-building the DOM one node at a time) are so ridiculous that I'm not even going there.
Sometimes document.write is the thing to use. The fact that it is one of the oldest methods in JavaScript is not a point against it, but a point in its favor - it is highly optimized code which does exactly what it was intended to do and has been doing since its inception.
It's nice to know that there are alternative post-load methods available, but it must be understood that these are intended for a different purpose entirely; namely modifying the DOM after it has been created and memory allocated to it. It is inherently more resource-intensive to use these methods if your script is intended to write the HTML from which the browser creates the DOM in the first place.
Just write it and let the browser and interpreter do the work. That's what they are there for.
PS: I just tested using an onload param in the body tag and even at this point the document is still open and document.write() functions as intended. Also, there is no perceivable performance difference between the various methods in the latest version of Firefox. Of course there is a ton of caching probably going on somewhere in the hardware/software stack, but that's the point really - let the machine do the work. It may make a difference on a cheap smartphone though. Cheers!
The question depends on what you are actually trying to do.
Usually, instead of doing document.write you can use someElement.innerHTML or better, document.createElement with an someElement.appendChild.
You can also consider using a library like jQuery and using the modification functions in there: http://api.jquery.com/category/manipulation/
This is probably the most correct, direct replacement: insertAdjacentHTML.
Try to use getElementById() or getElementsByName() to access a specific element and then to use innerHTML property:
<html>
<body>
<div id="myDiv1"></div>
<div id="myDiv2"></div>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
myDiv2.innerHTML = "<i>Content of second DIV element</i>";
</script>
</html>
Use
var documentwrite =(value, method="", display="")=>{
switch(display) {
case "block":
var x = document.createElement("p");
break;
case "inline":
var x = document.createElement("span");
break;
default:
var x = document.createElement("p");
}
var t = document.createTextNode(value);
x.appendChild(t);
if(method==""){
document.body.appendChild(x);
}
else{
document.querySelector(method).appendChild(x);
}
}
and call the function based on your requirement as below
documentwrite("My sample text"); //print value inside body
documentwrite("My sample text inside id", "#demoid", "block"); // print value inside id and display block
documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline
I'm not sure if this will work exactly, but I thought of
var docwrite = function(doc) {
document.write(doc);
};
This solved the problem with the error messages for me.
I'm trying to precisely fit a string into a certain width. This means the font-size changes depending on the string. I now use the following function, using jQuery:
function fontResize ( )
{
for (var i = $("#date").css("font-size").slice(0, -2); $("#date").width() < $("#clock").width(); i++)
$("#date").css("font-size", i.toString() + "px");
}
The idea is that I set the font-size in the CSS to the lowest possible value. I initialize the loop with this value and increment the font-size with 1 until the string is wider than the width of the containing element. The string in this case is "date" and the containing element is "clock".
Although this works, I think the main disadvantage is that the string has to be first drawn before the width can be determined. This means I cannot call this function before loading the body.
If anyone knows a better way to do this please let me know! Thanks.
To make sure you're getting all the styles and such applied to it that will be applied when the page is fully rendered, yes, you do want to put the element in the DOM (and in the right place in the DOM) before you do your measurement stuff. But you don't have to wait until everything else is there (unless you think it will affect the styling of the string you're measuring). You can put your code in a script block immediately after the element in question — no waiting for ready. The date element will be there and accessible, according to Google's Closure library engineers. E.g., if date is a span:
<body>
...
<span id="date">December 13th</span>
<script>fontResize();</script>
...
...
</body>
It's unfortunate to intermix code and markup like that (particularly if you have separate teams doing the markup and the code), but if your requirement is to size the text absolutely as soon as possible, that's how.
The above also assumes your fontResize function is already loaded (e.g., in a script block higher on the page). This is another reason it's unfortunate to mix markup and code like this, because normally of course you want to put your scripts at the bottom, just before closing the body tag.
However: It may be worth experimenting to see if you can do your resizing in the script you put just before the closing body tag instead. There'd be a small window of opportunity for the page not to look right, but quite small and of course pages tend to look a little funny as they load anyway. Then you wouldn't have the intermixing problem and wouldn't have to load your scripts early. You may find that the just-before-the-closing-body-tag is soon enough.
How about using the canvas, and the measureText method?
$(function () {
var canvas = $("canvas")[0];
var context = canvas.getContext("2d");
var text = "hello world";
context.font = "40pt Calibri";
var metrics = context.measureText(text);
alert(metrics.width);
});
We've all seen people who do this:
jQuery('a').each(function(){
jQuery(this)[0].innerHTML += ' proccessed';
});
function letsPoluteNS() {
polute = '';
for (morePolution = 0; morePolution < arguments.length; morePolution++)
polute.join(arguments[morePolution]);
return polute;
}
and so on. I was wondering what people have seen the most common JavaScript/jQuery technique that is slowing down the page and/or wasting time for the JavaScript engine.
I know that this question may not seem to fit into what's an accepted question, yet I'm asking "what is the most common accepted waste?"
I'm guilt of this. Basically using only the element's class in a jQuery selector. Instead of combining the class selector with the elements tag name.
<div></div>
<div class="hide"></div>
<div class="show"></div>
<div class="hide"></div>
<div class="hide again"></div>
$(".hide").hide();
Instead of the quicker
$("div.hide").hide()
Also this is inefficient, many people don't make use of the context parameter for selectors
$( selector, [ context ] )
$("#mydiv").click(function () {
$("#mydiv span").show();
}
Which can be handled better like this:
$("#mydiv").click(function () {
$("span", this).show();
}
You'll also see this:
$('#this').find('a').doSomeThing();
Know what's a lot more efficient? One selector that covers both will server you better...
$('#this a').doSomeThing();
It seems obvious, but you'll see it all the time.
Anything that has do to with tracking users and heavy publicity. Thats wasted space for sure.
I guess wrong use of stuff like using classes instead ids as selector in very complex html would slow thing down.
And ie of course.
Calling $.animate to animate elements should make the things slow down.
not declaring your vars from the getgo so they are cached, not using closures and repeating x number of the same function/call/etc but only changing id or class for each, using eval().