2

我有一个关于页面速度和代码优化的问题。我有一个页面几乎 100% 通过 AJAX 调用填充。我的问题是:对我来说,将几个空的 div、span 等任何内容编码到页面的 HTML 中,然后使用 javascript 填充这些元素是否更快?或者,在 javascript 中创建这些元素并插入和附加它们是否更快?我也不确定是否有很大的不同。因此,我们将不胜感激这方面的任何帮助/建议。

4

4 回答 4

6

几年前,我对此做了一个实验。innerHTML分配给元素的属性以创建复杂结构比使用重复createElement appendChild insertBefore等调用要快得多。我已经挖掘了我所做的关于它的帖子(到 Prototype & script.aculo.us 邮件列表);以下。

请记住,解析 HTML 并快速呈现它是浏览器所做的,并且它们经过高度优化可以做到这一点。如果您将其中包含复杂 HTML 结构的字符串分配给容器元素的innerHTML属性,则您正在从 JavaScript 层到浏览器的呈现层进行一次旅行,之后浏览器的解析和呈现代码可以不间断地进行。

相反,如果您使用 DOM API 构建一些复杂的结构,不仅会发生很多跨层旅行(JavaScript -> 浏览器 -> JavaScript),而且浏览器也必须使用 DOM API 而不是其内部结构。

因此,通常值得研究一个编写良好的 JavaScript 模板引擎(如果您想在客户端执行此操作)。这些通常会将模板“编译”为易于处理的形式,并且在处理特定数据集期间,它们将使用诸如通过将字符串构建为数组中的片段之类的技巧Array#push,然后通过Array#join传入获得最终结果""作为分隔符。对于大字符串,这可能比字符串连接更快,尽管它是否(以及在何种程度上)非常依赖于实现(Firefox 的 SpiderMonkey 与 Chrome 的 V8 与 IE 的 JScript),这innerHTML与与 DOM 不同,后者仅在有多快。

这是几年前我在谈论的邮件列表消息(基本上就是我上面所说的;哇,那是两年前的事了),这是它所指的 Pastie ,这是复制到 JSBin的,最后......这是代码:(请注意,代码并不是为了永远美丽和快乐,而是快速破解......不过,是的,我想我会破解一些东西现在好多了,两年后。)

可能值得将其转换为适用于jsPerf的东西。恐怕现在没时间这样做了。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<style>
#log {
    border-bottom:  1px solid black;
}
#log p {
    margin:     0;
    padding:    0;
}
</style>
<script type='text/javascript' src='//ajax.googleapis.com/ajax/libs/prototype/1/prototype.js'></script>
<script type='text/javascript'>
document.observe('dom:loaded', function() {
    $('btnDOMDirect').observe('click', useDOMDirect);
    $('btnPrototypeDOM').observe('click', usePrototypeDOM);
    $('btnHTML').observe('click', useHTML);

});

var numRows = 10;
var numCols = 10;

function usePrototypeDOM(evt)
{
    var table;
    var tbody;
    var tr;
    var td;
    var row;
    var col;
    var start;
    var end;

    start = (new Date()).getTime();

    table = new Element('table');
    tbody = new Element('tbody');
    table.appendChild(tbody);
    for (row = 0; row < numRows; ++row) {
        tr = new Element('tr');
        tbody.appendChild(tr);
        for (col = 0; col < numCols; ++col) {
            td = new Element('td');
            td.update('Row ' + row + ', col ' + col);
            tr.appendChild(td);
        }
    }
    $('targetTable').update(table);

    end = (new Date()).getTime();
    log('DOM took ' + (end - start) + 'ms');
}

function useDOMDirect(evt)
{
    var table;
    var tbody;
    var tr;
    var td;
    var row;
    var col;
    var start;
    var end;

    if (Prototype.Browser.IE) {
        alert("DOM direct doesn't work on IE because I used table elements.  Sorry.  The other two work.");
        return;
    }

    start = (new Date()).getTime();

    table = document.createElement('table');
    tbody = document.createElement('tbody');
    table.appendChild(tbody);
    for (row = 0; row < numRows; ++row) {
        tr = document.createElement('tr');
        tbody.appendChild(tr);
        for (col = 0; col < numCols; ++col) {
            td = document.createElement('td');
            td.update('Row ' + row + ', col ' + col);
            tr.appendChild(td);
        }
    }
    $('targetTable').update(table);

    end = (new Date()).getTime();
    log('DOM took ' + (end - start) + 'ms');
}

function useHTML(evt)
{
    var html;
    var row;
    var col;
    var start;
    var end;

    start = (new Date()).getTime();

    html = '<table><tbody>';
    for (row = 0; row < numRows; ++row) {
        html += '<tr>';
        for (col = 0; col < numCols; ++col) {
            html += '<td>Row ' + row + ', col ' + col + '</td>';
        }
        html += '</tr>';
    }
    html += '</tbody></table>';
    $('targetTable').update(html);

    end = (new Date()).getTime();
    log('HTML took ' + (end - start) + 'ms');
}

function log(msg)
{
    var l;
    var p;

    l = $('log');
    if (l) {
        p = new Element('p');
        p.update(msg);
        l.appendChild(p);
    }
}
</script>
</head>
<body>
<input type='button' id='btnDOMDirect' value='DOM Direct' />
<input type='button' id='btnPrototypeDOM' value='Prototype DOM' />
<input type='button' id='btnHTML' value='HTML' />
<div id='log'></div>
<div id='targetTable'></div>
</body>
</html>
于 2011-03-23T16:56:28.357 回答
0

如果您要创建大量元素,innerHTML 可能会快得多,但它不是官方 DOM 标准的一部分(尽管它得到了广泛的支持)。我的建议是使用骨架布局为页面提供服务,在页面本身中包含尽可能多的 HTML,然后获取对页面相关部分的引用并使用标准 DOM 方法插入值。

这应该相当快,将保持表示和逻辑分开,并且在未来站点更改或重新设计的情况下可能最终会更加灵活。

于 2011-03-23T17:03:22.300 回答
0

使用 javascript 来执行此操作总是会更慢,因为它在页面加载的顶部运行,而不是像在 HTML 中添加元素那样使用它。但是,如果没有 HTML 中的元素,您也可以说页面的实际负载较少(尽管不显着)。

不过,另一点是,javascript 在垃圾收集方面非常糟糕,因此如果您进行大量 DOM 调用,它最终会开始增加您的处理能力。

另外,如果您对维护语义网站感兴趣,您是否需要标记?没有javascript它会优雅地降级吗?等等等等。我想这取决于你想要采取的角度。

于 2011-03-23T16:58:07.393 回答
0

修改innerHTML而不是使用 DOM 方法。

根据Quirksmode上 W3C DOM 与 innerHTML 的基准测试,看起来所有测试过的浏览器在 HTML 上都比 DOM快得多

于 2011-03-23T17:03:59.617 回答