异步 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 中仍然如此)。有兴趣的同学可以 参看更详细的信息