很多人喜欢用innerHTML来实现动态内容,因为相比dom的操作来说,即简单又实用
但我却很少拿innerHTML来实现动态列表,innerHTML最多只是拿来显示一些名称等文本类的信息废话不多说,自己拿下面的代码做个实验,明白道理的自然OK,不明白的把运行结果贴出来看看就知道
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script language="javascript" type="text/javascript">
        function Append() {
            var n = parseInt(document.getElementById("tbTimes").value);
            var content = document.getElementById("tbContent").value;
            var startTime = (new Date()).getTime();
            var div = document.getElementById("divContent");
            div.innerHTML = "";
            for (var i = 0; i < n; i++) {
                var item = document.createElement("span");
                item.appendChild(document.createTextNode(content));
                div.appendChild(item);
            }
            var endTime = (new Date()).getTime();
            document.getElementById("tbTime").value = endTime - startTime;
        }
        function InnerHtml() {
            var n = parseInt(document.getElementById("tbTimes").value);
            var content = document.getElementById("tbContent").value;
            var startTime = (new Date()).getTime();
            var div = document.getElementById("divContent");
            div.innerHTML = "";
            for (var i = 0; i < n; i++) {
                div.innerHTML += "<span>" + content + "</span>";
            }
            var endTime = (new Date()).getTime();
            document.getElementById("tbTime").value = endTime - startTime;
        }
        function JoinInnerHtml() {
            var n = parseInt(document.getElementById("tbTimes").value);
            var content = document.getElementById("tbContent").value;
            var startTime = (new Date()).getTime();
            var div = document.getElementById("divContent");
            div.innerHTML = "";
            var result = [];
            //var result = "";
            for (var i = 0; i < n; i++) {
                result.push("<span>" + content + "</span>");
                //result += "<span>" + content + "</span>";
            }
            div.innerHTML = result.join("");
            //div.innerHTML = result;
            var endTime = (new Date()).getTime();
            document.getElementById("tbTime").value = endTime - startTime;
        }
    </script>
</head>
<body>
    内容<input id="tbContent" type="text" value=" [Hello World] " /><br />
    次数<input id="tbTimes" type="text" value="1000" /><br />
    耗时<input id="tbTime" type="text" /><br />
    <input type="button" value="appendChild" onclick="Append()"/>
    <input type="button" value="innerHTML" onclick="InnerHtml()" />
    <input type="button" value="join+innerHTML" onclick="JoinInnerHtml()" />&nbsp;
    <div id="divContent">
    </div>
</body>
</html>
从结果可以看出,同样次数的dom操作,绝对要比innerHTML要快得多
第三种方法看似最快,但实际上它只有一次innerHTML的赋值

解决方案 »

  1.   


    方法二慢在字符串的 "+" 操作... 不是innerHTML
      

  2.   


    额,修改来测试了下,确实是innerHTML消耗
    同样消耗大的还有document.getElementById() 方法
      

  3.   

    慢不在+,而在innerHTML,请看4楼回复
      

  4.   

    join+innerHTML平均在15左右
    appendChild平均在250左右。ie8,ff3
      

  5.   

    看也不用看就知道是dom慢了。每次往html元素中appendChild元素时,浏览器引擎都要进行重绘,可想效率有多差。
    还有,方法二明明就是慢在 + 号上了,js中字符串是不变的对象,都是执行字符串 + 都会重新创建一个字符串。
      

  6.   

    反驳LZ一个,"+" 操作是很慢的,不过这个程序主要是innerHTML频繁操作慢,"+"给忽略了function operateADD(){
               var startTime = (new Date()).getTime();
              var a="";
                for (var i = 0; i < 10000; i++) {
                    a += "<span>" + "</span>";
                }
              var endTime = (new Date()).getTime();
              alert(endTime - startTime);
    }function pushString(){
        var startTime = (new Date()).getTime();
         var result = [];
          for (var i = 0; i < 10000; i++) {
                result.push("<span>"  + "</span>");
          }
    result.join("");
    var endTime = (new Date()).getTime();
              alert(endTime - startTime);}结果显而易见
      

  7.   

    各有存在的理由,看怎么用,create出来的,后面还可以直接调用。
    innerHTML插进去的想要接着用多少有些麻烦。
      

  8.   

    看了下 +虽然确实占较长时间,但是在通过10000次计算也才1380 而LZ那个1000次计算就有18200 10000次计算所花时间不到1000次计算所花时间的1/10,可见主要耗时的还是innerHTML
      

  9.   

    很赞成,innerHTML插进去的东西,你还得花心思给它准备N个id,然后才能通过document.getElementById来取到。而dom操作基本上可以抛开id
      

  10.   

    我从不认为字符串的+操作会慢,这是10万次的字符串+操作,与join对比一下就知道了function Test() {
        var str = "";
        //var str = [];
        var startTime = (new Date()).getTime();
        for (var i = 0; i < 100000; i++) {
            str += "xxxx";
            //str.push("xxxx");
        }
        //var result = str.join("");
        var endTime = (new Date()).getTime();
        alert( endTime-startTime);
    }
      

  11.   

    理论上说,同样是从最初的字符串变成最终的DOM对象,如果浏览器实现没有问题的话,有什么理由让两者花掉的时间不一样呢?
    首先第二种方法就不说了,只需要1000次的事情做了500500次,谁真这么做谁有毛病;
    第一种和第三种方法,理想情况下说应该是差别不大,可能的影响有:
    1.前面有人提到了,每次DOM操作都要刷新页面,这是个很浪费的操作。但是这是可以优化的,如果浏览器对此做了优化,就不会造成这么严重的影响。
    2.字符串操作好像都被妖魔化了,大家都觉得是洪水猛兽,那有多少人真的去测过字符串操作呢?相信多数人都是从其他语言的字符串操作推测出来的吧?不可以说完全没有影响,不过其实没有想象的那么猛。
    个人猜测可能是因为第一个原因,Chrome下LZ的程序测试结果是第一种最快,而其他浏览器下都是第三种最快。但是就算在Chrome下,如果刷新页面后第一次操作就试第三种,其结果跟第一种方式几乎是一样快的,这个就解释不了了。
    结论:谁快谁慢还是跟浏览器有关,并且innerHTML往往用起来更方便,因为AJAX返回的始终是字符串,又不是DOM对象。所以我还是偏向于innerHTML
      

  12.   

    Chrome浏览器我总感觉还不够成熟,我正在开发的一个项目始终无法稳定运行在Chrome2.0上,而与它一个娘生的Safari却可以。
    另外,innerHTML的效率是没问题的,只是有点随意,对我来说真正用得多的是插入位置可控的insertAdjacentHTML。
      

  13.   

    我的项目也无法运行在Chrome上,连3.0都还不行。我的是因为调用了XPath相关函数,而Chrome从beta起就一直有一个BUG#671,导致XPath调用失败。除此之外还没有遇到过其他的问题。不知道你的项目运行不了是什么原因?
    很少用到insertAdjacentHTML,查了一下文档小试了一下,好像浏览器不兼容。Chrome是可以的,Firefox不支持。
    Chrome的JS V8引擎效率非常高,虽然在Sun的评测下综合得分稍低于Firefox3.5,但是在Google自己的评测网站下却是Chrome遥遥领先Firefox3.5。就我自己使用到的部分来看,总体感觉是Chrome的JS效率要高于其他浏览器,非常喜欢。
      

  14.   

    innerHTML 最好不要用 innerHTML+="..."来实现,不然里面生成的DOM 都不能正常操作,换做var str=$.innerHTML,然后用 str+="..." 最后再$.innerHTML=str
      

  15.   


    我的项目是一个纯ajax的项目,有大量的js代码,GC下经常出现当前窗口不响应的情况。
    另外insertAdjacentHTML原本只有IE支持,不过FF有insertBefore方法,可以代替。
    以下是可以跨浏览器的方法
    window.insertHTML = function(where, el, html){
    if(el.insertAdjacentHTML){
    switch(where){
    case "BeforeBegin": el.insertAdjacentHTML(where, html); return el.previousSibling; break;
    case "AfterBegin": el.insertAdjacentHTML(where, html); return el.firstChild; break;
    case "BeforeEnd": el.insertAdjacentHTML(where, html); return el.lastChild; break;
    case "AfterEnd": el.insertAdjacentHTML(where, html); return el.nextSibling; break;
    }
    throw '未知的插入点 -> "' + where + '"';
    }else{
    var range = el.ownerDocument.createRange(); var frag;
    switch(where){
    case "BeforeBegin": range.setStartBefore(el); frag = range.createContextualFragment(html); el.parentNode.insertBefore(frag, el); return el.previousSibling; break;
    case "AfterBegin": if(el.firstChild){range.setStartBefore(el.firstChild); frag = range.createContextualFragment(html); el.insertBefore(frag, el.firstChild); return el.firstChild;}else{el.innerHTML = html; return el.firstChild;} break;
    case "BeforeEnd": if(el.lastChild){range.setStartAfter(el.lastChild); frag = range.createContextualFragment(html); el.appendChild(frag); return el.lastChild;}else{el.innerHTML = html; return el.lastChild;} break;
    case "AfterEnd": range.setStartAfter(el); frag = range.createContextualFragment(html); el.parentNode.insertBefore(frag, el.nextSibling); return el.nextSibling; break;
    }
    throw '未知的插入点 -> "' + where + '"';
        }
    }