页面速度优化:使用 javascript 与 html 写入 DOM

发布于 2024-10-25 23:43:23 字数 190 浏览 4 评论 0原文

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

I have a question concerning page speed and code optimization. I have a page which is populated almost 100% through AJAX calls. My question is: is it faster for me to code several empty divs, spans, whatever into the HTML of the page, then fill those elements using javascript? Or, is it faster to create these elements in javascript and insert and append them?
I'm not sure if there IS a big difference either. So, any help/advice in this area would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寄离 2024-11-01 23:43:23

几年前,我对此做了一个实验。分配给元素的 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>

A couple of years back, I did an experiment on this. It's much faster to assign to the innerHTML property of an element to create a complex structure than it is to use repeated createElement appendChild insertBefore etc. calls. I've dug up the post I did about it (to the Prototype & script.aculo.us mailing list); below.

Remember that parsing HTML and rendering it quickly is what browsers do, and they're highly optimized to do it. If you assign a string with a complex HTML structure in it to a container element's innerHTML property, you're making one trip from the JavaScript layer to the browser's rendering layer, after which the browser's parsing and rendering code can proceed uninterrupted.

In contrast, if you're building that some complex structure using the DOM API, not only is there a lot of cross-layer travel happening (JavaScript -> browser -> JavaScript), but the browser is also having to work with the DOM API rather than its internal structures.

Consequently, it's usually worth looking at a well-written JavaScript templating engine (if you want to do this client-side). These will usually "compile" the template once into an easily processed form, and during processing for a particular data set, they'll use tricks like building up the string as fragments in an array via Array#push, and then getting the final result via Array#join passing in "" as the separator. For large strings, that can be faster than string concatenation, although whether it is (and to what degree) is very implementation dependent (Firefox's SpiderMonkey vs. Chrome's V8 vs. IE's JScript), unlike the innerHTML vs. DOM thing, which only varies in how much faster it is.

Here's the mailing list message from a couple of years back I was talking about (saying basically what I say above; wow, it was two years ago), here's the Pastie it refers to, here's that copied to JSBin, and finally...here's the code: (Note that the code is not intended to be a thing of beauty and a joy forever, it was a quick hack... Still though, yeesh, I'd like to think I'd hack up something a bit better now, two years later.)

It may be worth converting this into something that will work on jsPerf. No time to do that now, I'm afraid.

<!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>
帅的被狗咬 2024-11-01 23:43:23

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

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

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

It will always be slower using javascript to do this because it runs on top of the page load, rather than with it, as adding elements to the HTML would. However, you could also say that the actual load of the page is less (although not significantly) without having the elements in HTML.

The other point is, though, javascript is pretty bad at garbage collection so if you're making loads of DOM calls it will eventually start to add up in your processing power.

Plus there is also if you're interested in maintaining a semantic website, are you tags necessary? Does it degrade gracefully without javascript? Etc etc. It depends on the angle you are wanting to take I suppose.

惜醉颜 2024-11-01 23:43:23

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

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

If you're creating lots of elements innerHTML can be much faster, however it's not a part of the official DOM standard (though it is widely supported). My recommendation would be to serve the page with a skeleton layout, including as much HTML as you can in the page itself, and then grab references to relevant parts of the page and plug in the values with standard DOM methods.

This should be reasonably fast, will keep the presentation and logic separate, and will probably end up being more flexible in the case of future site changes or redesigns.

﹉夏雨初晴づ 2024-11-01 23:43:23

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

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

Modify innerHTML instead of using DOM methods.

According to this benchmark of W3C DOM vs innerHTML on Quirksmode, it looks like all tested browsers are much faster at HTML than DOM.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文