innerHTML 的些摘记

作者:手气不错 发布时间:May 31, 2009 分类:JavaScript

异步 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. 渔隐 May 31st, 2009 at 08:22 pm #1
    渔隐

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

  2. lifesinger May 31st, 2009 at 08:28 pm #2
    lifesinger

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

  3. 长天 June 1st, 2009 at 09:01 am #3
    长天

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

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

  4. lanqy June 1st, 2009 at 09:23 am #4
    lanqy

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

  5. 明城 June 1st, 2009 at 10:26 am #5
    明城

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

  6. 盒子 June 1st, 2009 at 10:26 am #6
    盒子

    路过+学习

  7. rokin June 1st, 2009 at 10:39 am #7
    rokin

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

  8. OoSleePinG June 2nd, 2009 at 10:54 am #8
    OoSleePinG

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

  9. Mr.Right June 8th, 2009 at 09:58 am #9
    Mr.Right

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

  10. 手气不错 June 8th, 2009 at 12:54 pm #10
    手气不错

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

  11. robben June 9th, 2009 at 01:06 pm #11
    robben

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

  12. infinte August 7th, 2009 at 06:02 pm #12
    infinte

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

  13. 手气不错 August 7th, 2009 at 11:15 pm #13
    手气不错

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

  14. paper November 24th, 2009 at 11:16 am #14
    paper

    tbody 中插入 innerHTML陷阱。

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

  15. Shanpeng December 25th, 2009 at 06:29 pm #15
    Shanpeng

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

Yahoo 统计