innerHTML 的些摘记May 31, 2009

异步 innerHTML

innerHTML 插入节点的性能的问题,通常是我们最关注的。在回答这问题时James Padolsey 给出了他的解决方案,看到上述代码不仅赞叹了下:

function asyncInnerHTML(HTML, callback) {
    var temp = document.createElement('div'),
        frag = document.createDocumentFragment();
    temp.innerHTML = HTML;
    (function(){
        if(temp.firstChild) {
            frag.appendChild(temp.firstChild);
            setTimeout(arguments.callee, 0);
        } else {
            callback(frag);
        }
    })();
}
  1. 充分利用闭包解决 IE6 的内存溢出问题
  2. 使用延时 0 将操作从队列中拉出,防止浏览器假死
  3. Document Fragment 给予我们个相当好的沙盘,只是我们经常忘记了它
  4. 回调的节点可以使用 DOM 标准的手法(appendChild)插入

了解了参数就很容易调用,例如

var htmlStr = '<div><p>...</p><p>...</p><div><div>...</div>';
asyncInnerHTML(htmlStr, function(fragment){
    document.body.appendChild(fragment);
});

再次不禁赞叹下!

组织 innerHTML 字符串

说到 innerHTML ,通常在这操作之前会有大部分的字符串操作用于连接节点。考虑下面的三种做法,有何不同

方式一

var arr = ['item 1', 'item 2', 'item 3', ...];
for (var i = 0, l = arr.length, list = ''; i < l; i++) {
    list += '<li>' + arr[i] + '</li>';
}
list = '<ul>' + list + '</ul>';

方式二

var arr = ['item 1', 'item 2', 'item 3', ...];
for (var i = 0, l = arr.length, list = []; i < l; i++) {
    list[list.length] = '<li>' + arr[i] + '</li>';
}
list = '<ul>' + list.join('') + '</ul>';

方式三

var arr = ['item 1', 'item 2', 'item 3', ...];
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';

详细的对比测试在这里(没错,还是 James Padolsey 那小子的 Blog)。同时,PPK 也整理了份有关 innerHTML 的速度测试报告

IE 的陷阱

对于 IE,innerHTML 有个不大不小的陷阱(via),就是在 tbody 中插入 innerHTML 时,会报莫名的“未知的运行错误”。

测试地址在这里(经过测试,在 IE8 中仍然如此)。有兴趣的同学可以参看更详细的信息

已有 15 条评论

  1. 沙发是我的,明哥写的很有深度,如果有实例就更好了

  2. lifesinger lifesinger

    推荐通读James Padolsey那小子的blog,学会不少好东西,嘿嘿

  3. 长天 长天

    方式三, 技术含量之高, 堪称经典, 它让我回想起了以前看到的, 它的一个经典用法: 复制字符串

    /*
    * @params:
    str --> 待复制的字符串;
    num --> 复制的次数
    */
    function repeatStr(str, num) {
    var arr = new Array(num + 1)
    return arr.join(str);
    }

  4. lanqy lanqy

    为什么把list = []; list = ' ';写在for里呢?

  5. @lanqy 其实放在外面也是一样,约定是和循环相关的变量都放在初始化部分了而已 :^)

  6. 路过+学习

  7. rokin rokin

    “IE 的陷阱” 这里。会不会是因为 table 是readonly 的。

  8. OoSleePinG OoSleePinG

    IE的innerHTML问题的不只是tbody ,table,tr,select,fieldset标签都会出现问题,好在一般的js库中都有解决方案。

  9. 页脚的“浙ICP备 07002356号”在IE6下多出了一个“号”字,希望能看到你把这个问题解决掉

  10. @Mr.Right 过段时间改模板,这个问题暂时就先扔着了 :^)

  11. robben robben

    James Padolsey的那段代码,“充分利用闭包解决 IE6 的内存溢出问题”,是什么意思?

  12. 路过+学习+申请加友情链接(估计没希望):
    http://infinte.yo2.cn

  13. @infinte 暂时没有友情链接的考虑,不过如果你有好的内容,我会在以后的 Blog 中链接你的文章的,这样也更有意义些 :^)

  14. tbody 中插入 innerHTML陷阱。

    因为IE中tbody的内容只读,不支持修改。

  15. 非常熟悉,^_^!第三种拼接字符串的方式非常的不错,以前看过frag的使用方式,以及arguments.callee的使用,arguments.callee使用得当,代码将会简洁不少。
    我也广告一下:
    下面是我写的一个利用arguments.callee写的一个检测DOM是否加载完毕的小对象:
    http://www.ilovejs.net/archives/51

Yahoo 统计