简体   繁体   English

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

[英]page speed optimization: writing to DOM using javascript vs. html

I have a question concerning page speed and code optimization. 我有一个关于页面速度和代码优化的问题。 I have a page which is populated almost 100% through AJAX calls. 我有一个页面,其中几乎100%通过AJAX调用填充。 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? 我的问题是:对我来说,将几个空的div,spans编码成页面的HTML更快,然后使用javascript填充这些元素会更快吗? Or, is it faster to create these elements in javascript and insert and append them? 还是在javascript中创建这些元素并插入和附加它们更快? I'm not sure if there IS a big difference either. 我不确定是否也有很大的不同。 So, any help/advice in this area would be greatly appreciated. 因此,在此领域的任何帮助/建议将不胜感激。

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. 分配给元素的innerHTML属性以创建复杂结构比使用重复的createElement appendChild insertBefore等调用要快得多。 I've dug up the post I did about it (to the Prototype & script.aculo.us mailing list); 我已经挖了关于它的帖子(到Prototype&script.aculo.us邮件列表); below. 下面。

Remember that parsing HTML and rendering it quickly is what browsers do , and they're highly optimized to do it. 请记住,解析HTML并快速呈现它是浏览器的工作 ,并且它们已经高度优化以做到这一点。 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. 如果将具有复杂HTML结构的字符串分配给容器元素的innerHTML属性,那么您就需要从JavaScript层到浏览器的呈现层进行一次旅行,此后浏览器的解析和呈现代码可以不间断地进行。

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. 相反,如果您使用DOM API构建某种复杂的结构,不仅会发生很多跨层旅行(JavaScript->浏览器-> JavaScript),而且浏览器还必须使用DOM。 API,而不是其内部结构。

Consequently, it's usually worth looking at a well-written JavaScript templating engine (if you want to do this client-side). 因此,通常值得研究一个编写良好的JavaScript模板引擎(如果要在客户端进行)。 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. 这些通常会将模板一次“编译”为易于处理的形式,并且在处理特定数据集的过程中,它们将使用一些技巧,例如通过Array#push将字符串构建为数组中的片段,然后获得最终结果。通过Array#join传递""作为分隔符。 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. 对于大型的字符串,可以比字符串连接快,但无论是(到什么程度)是非常依赖于实现(Firefox的SpiderMonkey的与Chrome的V8与IE的JScript中),不像innerHTML与DOM的事情,这只是改变在快。

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.) 是几年前我在谈论的邮件列表消息(基本上说了我上面所说的;哇,是两年前的事了), 这是它所指的Pastie,这是复制到JSBin上的消息 ,最后...这是代码:( 请注意,代码并不是永远要成为美的和快乐的东西,这是一个快速的技巧……不过,是的,我想我还是会有点技巧。现在好了,两年后。)

It may be worth converting this into something that will work on jsPerf . 可能值得将其转换为可在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>

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. 使用javascript来执行此操作总是比较慢,因为它是在页面加载的顶部运行,而不是像在HTML上添加元素那样,是在页面加载之上运行的。 However, you could also say that the actual load of the page is less (although not significantly) without having the elements in HTML. 但是,您也可以说没有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. 但是,另一点是,JavaScript在垃圾回收方面非常糟糕,因此,如果您要进行DOM调用,则最终将开始增加您的处理能力。

Plus there is also if you're interested in maintaining a semantic website, are you tags necessary? 另外,如果您有兴趣维护语义网站,还需要标记吗? Does it degrade gracefully without javascript? 没有javascript,它是否可以优雅地降级? Etc etc. It depends on the angle you are wanting to take I suppose. 等等等等。我想这取决于您要采取的角度。

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). 如果要创建很多元素,则innerHTML可以更快,但是它不是官方DOM标准的一部分(尽管得到了广泛支持)。 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. 我的建议是为页面提供框架布局,包括尽可能多的HTML内容,然后获取对页面相关部分的引用,并使用标准DOM方法插入值。

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. 这应该是相当快的,它将表示和逻辑分开,并且可能在将来更改站点或重新设计时变得更加灵活。

Modify innerHTML instead of using DOM methods. 修改innerHTML而不是使用DOM方法。

According to this benchmark of W3C DOM vs innerHTML on Quirksmode, it looks like all tested browsers are much faster at HTML than DOM. 根据W3C DOM与 Quirksmode上的innerHTML的基准 ,看来所有经过测试的浏览器在HTML上的运行速度都比DOM快得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM