When innerHTML isn’t Fast Enough
This post isn't about the pros and cons of innerHTML
vs. W3C DOM methods. That has been hashed and rehashed elsewhere. Instead, I'll show how you can combine the use of innerHTML
and DOM methods to make your code potentially hundreds of times faster than innerHTML
on its own, when working with large numbers of elements.
In some browsers (most notably, Firefox), although innerHTML
is generally much faster than DOM methods, it spends a disproportionate amount of time clearing out existing elements vs. creating new ones. Knowing this, we can combine the speed of destroying elements by removing their parent using the standard DOM methods with creating new elements using innerHTML
. (This technique is something I discovered during the development of RegexPal, and is one of its two main performance optimizations. The other is one-shot markup generation for match highlighting, which avoids needing to loop over matches or reference them individually.)
The code:
function replaceHtml(el, html) { var oldEl = typeof el === "string" ? document.getElementById(el) : el; /*@cc_on // Pure innerHTML is slightly faster in IE oldEl.innerHTML = html; return oldEl; @*/ var newEl = oldEl.cloneNode(false); newEl.innerHTML = html; oldEl.parentNode.replaceChild(newEl, oldEl); /* Since we just removed the old element from the DOM, return a reference to the new element, which can be used to restore variable references. */ return newEl; };
You can use the above as el = replaceHtml(el, newHtml)
instead of el.innerHTML = newHtml
.
innerHTML is already pretty fast...is this really warranted?
That depends on how many elements you're overwriting. In RegexPal, every keydown event potentially triggers the destruction and creation of thousands of elements (in order to make the syntax and match highlighting work). In such cases, the above approach has enormous positive impact. Even something as simple as el.innerHTML += str
or el.innerHTML = ""
could be a performance disaster if the element you're updating happens to have a few thousand children.
I've created a page which allows you to easily test the performance difference of innerHTML
and my replaceHtml
function with various numbers of elements. Make sure to try it out in a few browsers for comparison. Following are a couple examples of typical results from Firefox 2.0.0.6 on my system:
1000 elements... innerHTML (destroy only): 156ms innerHTML (create only): 15ms innerHTML (destroy & create): 172ms replaceHtml (destroy only): 0ms (faster) replaceHtml (create only): 15ms (~ same speed) replaceHtml (destroy & create): 15ms (11.5x faster) 15000 elements... innerHTML (destroy only): 14703ms innerHTML (create only): 250ms innerHTML (destroy & create): 14922ms replaceHtml (destroy only): 31ms (474.3x faster) replaceHtml (create only): 250ms (~ same speed) replaceHtml (destroy & create): 297ms (50.2x faster)
I think the numbers speak for themselves. Comparable performance improvements can also be seen in Safari. In Opera, replaceHtml
is still typically faster than innerHTML
, but by a narrower margin. In IE, simple use of innerHTML
is typically faster than mixing it with DOM methods, but not by nearly the same kinds of margins as you can see above. Nevertheless, IE's conditional compilation feature is used to avoid the relatively minor performance penalty, by just using innerHTML
with that browser.
Pingback by jQuery html() optimieren - XHTMLforum on 14 November 2008:
[…] html() optimieren Hallo, ich möchte gerne die jQuery html() Funktion, wie hier beschrieben optimiren. Hier mein aktueller Versuch: […]
Pingback by Writing better javascript - Part 3 « Vish’s ramblings on 18 November 2008:
[…] Check out the benchmarks on the performance benefits of using the ‘innerHTML’ property over the DOM manipulation methods here at QuirksMode. If you are a bigger stickler for performance and the gains from using ‘innerHTML’ doesn’t satisfy you, then you might consider using the ‘replaceHTML’ function below as per the suggestions posted here. […]
Comment by Paul on 24 February 2009:
looks good… one question… what licence is this released under? can I include it in a GPLv3 project? 🙂
Comment by Steven Levithan on 26 February 2009:
@Paul, it’s released under the MIT license, and yes it’s compatible with GPLv3.
Comment by caii on 9 April 2009:
fn=function (){……}
el.addEventListener(‘click’,fn , false);
replaceHtml(el,html);
when click on e1,fn can’t work,
fix it
Comment by jag on 31 July 2009:
Hi, wont be another a**hole that tells you your code sucks and my approach is better than yours.
I just like to thank you for sharing such a great code! This is so cool!!!!Yebah!
Pingback by Browser detection is still useful | Karmagination on 31 July 2009:
[…] benchmark results are here. Both of the code snippets are cross-browser compatible. The Gecko engine runs faster using method […]
Comment by jag on 31 July 2009:
BTW, i visited “The Big Dumb Developer” and tested his workaround and found out how sucky the solution was that was supposed to, as said to be-“better.” I’d say F*** off dude! again, Kudos for this post! (:
Comment by Hello Kitty on 28 August 2009:
em… how about enclose the new HTML message with another node, then assign to innerHTML?
i.g.
node.innerHTML = +message+ ?
This may reduce the time FF need to clean up the things?
Comment by Hello Kitty on 28 August 2009:
node.innerHTML = <span>,+message+</span> ?
Comment by Najib on 5 March 2010:
great solution. i´m using it and it improved my divs load performance.
thx.
Comment by bernhold on 25 March 2010:
c00l 🙂
Comment by dgatwood on 17 April 2010:
Tried this today as an attempt to improve FireFox innerHTML performance on a page that takes over a minute to load (versus only 20 seconds in Safari), but no joy. Performance of replaceChild was identical to innerHTML (or at least within the ~1 second margin of error) in both Safari 4.0.5 and FF 3.6. Maybe it’s still useful for older browsers, but I sure do with FireFox’s innerHTML performance wasn’t so awful.
Apparently the best I can do is disable incremental loading/display in FireFox. *sigh* If anybody has any better suggestions (that don’t involve chunking and parsing the HTML in JavaScript), I’d love to hear them.
Comment by dgatwood on 17 April 2010:
Err.. I sure do wish FF’s innerHTML performance weren’t so awful. Gotta watch the typos.
Comment by dgatwood on 17 April 2010:
I spoke too soon. My code was getting bounded by FireFox’s awful string length performance on the XMLHttpRequest’s contentText. That performance hit so completely overshadowed the innerHTML performance that I have no idea whether this helped or not…. *grrrr*
Comment by Samir on 22 April 2010:
Thank you for sharing your code, how can I change the code below to use your code instead. It is very slow loading with IE when the text is so large > 15 pages, though it is much faster in firefox.
Thanks
var v;
for (var i=sseq;i<=eseq;++i){
v=i-t;ttext[0].innerHTML+=" “+etext[i]+” “+” (” +””+v+”)” +”\u00A0″+” “;
}
Comment by Lucian Yao on 30 April 2010:
Great!!
I was just in this sort of trouble, your code improved the speed of my website significantly and saved my ass!!
Thank you!!
Comment by dreamweb on 11 July 2010:
its great – thank you
Pingback by Startup Dreams » Blog Archive » Faster than inner.HTML: Quick fixes with replaceHtml() - Living, Learning and Coding on 3 August 2010:
[…] implementation of replaceHtml(), a javascript alternative to the innerHTML which can be found here. Both innerHTML and replaceHtml() are way faster than DOM methods when it comes to inserting […]
Pingback by ????? innerHTML ????? ! | Mouse.z on 13 August 2010:
[…] http://blog.stevenlevithan.com/archives/faster-than-innerhtml 1000 elements… innerHTML (destroy only): 156ms innerHTML (create only): 15ms innerHTML (destroy […]
Comment by Al on 10 October 2010:
Thanks! It really speed up loading on firefox while using dhtml on big object.
Very good job!
Beer for you! ^^
Comment by Rick on 11 November 2010:
I noticed no performance improvements over a series of HUGE html inserts. Apparently it became like 1% slower with this – but at least I could isolate the HTML changing part of my code to profile on Firebug 🙂
Comment by Dan Beam on 25 March 2011:
By the way, this would be *even faster* if you simply assign the function once based on the conditional compilation being present or not, like so:
// for everybody except IE
function replaceHtml(el, html) {
var oldEl = typeof el === “string” ? document.getElementById(el) : el;
var newEl = oldEl.cloneNode(false);
newEl.innerHTML = html;
oldEl.parentNode.replaceChild(newEl, oldEl);
/* Since we just removed the old element from the DOM, return a reference
to the new element, which can be used to restore variable references. */
return newEl;
};
// Pure innerHTML is slightly faster in IE, so change the function
/*@cc_on
function replaceHtml(el, html) {
var oldEl = typeof el === “string” ? document.getElementById(el) : el;
oldEl.innerHTML = html;
return oldEl;
}
@*/
https://gist.github.com/887592 (in case my text is messed up)
Pingback by 10 jQuery HTML Plugins | jQuery4u on 5 September 2011:
[…] This plug-in is a simple port based on Steven Levithan’s replaceHtml function, designed to speed up the native innerHTML Javascript assignment property and as a replacement for jQuery’s html() function. Source […]
Comment by Julien Kronegg on 26 January 2012:
Replacing the element may cause some problems since existing javascript objects may refer to the replaced object. This will cause two kind of problems because the old and new elements will be referenced: 1) incoherence 2) memory leak.
I prefer “The Big Dump Developer” solution which avoids the incoherence and memory leak.
Comment by PherricOxide on 11 July 2012:
Doesn’t seem to have any effect on Firefox anymore, but it still has huge speed boosts in Chrome 18. I was using innerHTML to push a very large table (500+ rows, 15 columns). It went from 70ms to 40ms using the replaceHTML function.
Comment by Neil Green on 27 October 2012:
Very nice technique. I utilized it in my FastDomSorter project for a big performance boost: https://github.com/ngreen77/FastDomSorter
Comment by Joe D on 3 May 2014:
Absolutely awesome. Been needing this solution for a long time. Bravo. The performance gain is so great.
Comment by Norbert on 14 May 2014:
I ran all the tests in Chrome. They are the same for both. For fewer elements, the innerHTML is faster sometimes by 1-2 ms, for 10k and 14k, replaceHTML is faster by 3-4 ms.
Also, good to see how browsers improved in 7 years. My results for 15K in Chrome:
15000 elements…
innerHTML (destroy only): 34ms
innerHTML (create only): 18ms
innerHTML (destroy & create): 55ms
replaceHtml (destroy only): 34ms (~ same speed)
replaceHtml (create only): 18ms (~ same speed)
replaceHtml (destroy & create): 51ms (~ same speed)
Done.
Comment by Google on 25 July 2014:
Hi! I just wanted to ask if you ever have any issues with hackers?
My last blog (wordpress) was hacked and I ended up losing months of hard work due to no data backup.
Do you have any solutions to prevent hackers?
Comment by Vanat on 1 October 2015:
I would like to make updated tests on your function… but your link is broken. Could you share it again? Thanks =D
Comment by ????? ???? ???????? ?? on 8 February 2017:
????????????????????????!
??????2017?????????????
?? ???????????????? ??????!
???????????????
???????????????????????????
? 100%????????
? ???????(????)!
???????????????????????
????? ???? ???????? ?? http://copysale.net/Copy-sale-7652-_25E3_2583_25AB_25E3_2582_25A4_25E3_2583_25B4_25E3_2582_25A3_25E3_2583_2588_25E3_25830A8265AC63.htm
Comment by ????? ?? ??????? ?? on 8 February 2017:
?????????????????????????
?????????????????N???????????????
????????,?2?9??????????????????????!
????? ?? ??????? ?? http://kopi78.com/products_bigbrandId_6.html
Comment by ????? ???? ??????? ???? on 8 February 2017:
2017?????-??
????????????????????????????
????????????????????????????
????????(????)
????????????????.
????????????????????!
????? ???? ??????? ???? http://copysale.net/Copy-sale-322-_25E3_2583_2590_25E3_2583_25AC_25E3_2583_25B3_25E3_2582_25B7_25E3_2582_25A2_25E3_2582_05758FFC80.htm