当前位置: 动力学知识库 > 问答 > 编程问答 >

javascript - DOM nodes creation vs perfomance

问题描述:

I have a function that dynamically creates DOM nodes to accomodate GPS JSON data from a server. As number of nodes increases, browser performance also

degrades. Is there any means to rewrite/tweak the function to improve performance? The simplified node creation part of the function works as shown below:

var table = document.createElement('table');

var tbody = document.createElement('tbody');

table.appendChild(tbody);

for(var i = 0; i<3000;i++){

var tr = document.createElement('tr');

for(var j=0;j<50;j++){

var td = document.createElement('td');

td.style.backgroundColor="#a"+j%10+'c';

tr.appendChild(td);

}

tbody.appendChild(tr);

}

网友答案:

You might want to consider using some kind of Recyclable List.

Such lists recycle their elements by deleting DOM nodes that lie outside the viewport and recreating them when currently viewed.

Long story short - only currently-viewed DOM nodes exist in the DOM at any given time

Another technique is to use a fixed number of cells which you then fill with data according to where the user is scrolled

AFAIK there's no other way to go about this - naively creating 150,000 DOM nodes would completely decimate your scrolling performance

Some Examples

  • An example in pure JS
  • An example that's build on top of Polymer
  • Another example build on top of React

Here's how the pure JS example handles this:

Source: http://elliottsprehn.com/personal/infinite-scroll.html

<!DOCTYPE html>
<style>
    * { box-sizing: border-box; }
    ul, li { list-style-type: none; padding: 0; margin: 0; }

    h1 { font-size: 1.2em; }

    #infinite-list {
        width: 300px;
        border: 1px solid #ccc;
        margin: 1em;
        position: relative;
    }

    #infinite-list .scroll-view {
        overflow-y: scroll;
        height: -webkit-calc(20em + 2px);
    }

    #infinite-list ul {
        position: absolute;
        top: 0;
        width: -webkit-calc(100% - 16px);
    }

    #infinite-list li { 
        height: 2em;
        line-height: 2em;
        padding-left: 1em;
        border-bottom: 1px solid #ccc;
    }

    #infinite-list li:last-child { 
        border-bottom: none;
    }

    #infinite-list .scroll-view .spacer {
        height: -webkit-calc(2em * 20000);
    }
</style>

<h1>Infinite Scrolling with a fixed number of DOM nodes</h1>

<div id="infinite-list">
    <div class="scroll-view">
        <ul>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
            <li><a href=""></a></li>
        </ul>
        <div class="spacer"></div>
    </div>
</div>

<script>
(function() {
    function randRange(low, high) {
         return Math.floor(Math.random() * (high - low)) + low;
    }

    function randPick(array) {
        return array[randRange(0, array.length)];
    }

    // Randomly create a bunch of test data.
    var tlds = ['.com', '.net', '.org', '.edu', '.co.uk'];
    var domains = ['google', 'facebook', 'yahoo', 'apple', 'youtube', 'amazon'];
    var data = [];
    for (var i = 0; i < 20000; ++i) {
        data.push(i + ' ' + randPick(domains) + randPick(tlds));
    }

    var list = document.querySelector('#infinite-list');
    var listItems = document.querySelectorAll('#infinite-list li');
    var scrollView = document.querySelector('#infinite-list .scroll-view');

    var itemHeight = listItems[0].getBoundingClientRect().height;
    var previous;

    // Propagate scrolling with the mouse wheel.
    list.onmousewheel = function(e) {
        var delta = e.wheelDeltaY;
        if (Math.abs(delta) < itemHeight) {
            delta = itemHeight * (delta > 0 ? 1 : -1);
        }
        scrollView.scrollTop -= delta;
    };

    function update() {
        var current = scrollView.scrollTop;
        if (previous == current) {
            webkitRequestAnimationFrame(update);
            return;
        }
        previous = current;
        var first = Math.ceil(current / itemHeight);
        for (var i = 0; i < listItems.length; ++i) {
            listItems[i].firstElementChild.textContent = data[first++];
        }
        webkitRequestAnimationFrame(update);
    }
    update();

})();
</script>
网友答案:

If you are not already, you might want to hide the element you are creating nodes in, and only show it at the end of your loop.

E.g. set display:none; on it while you are working on it, and then switch back to display:block; (or whichever it is) afterwards.

Update: Actually, you don't even need to hide it, though that's one way to do it. The cleaner way is to wait with adding your table to the document until you finish adding all nodes to it, and then only add it to the body afterwards.

var table = document.createElement('table');
var tbody = document.createElement('tbody');
for(var i = 0; i<3000;i++){
    var tr = document.createElement('tr');
    for(var j=0;j<50;j++){
        var td = document.createElement('td');
        td.innerHTML = "#a"+j%10+'c';
        td.style.backgroundColor="#a"+j%10+'c';
        tr.appendChild(td);
    }
    tbody.appendChild(tr);
}
table.appendChild(tbody);
document.body.appendChild(table);
网友答案:

It might help to enlist the browser's help by making a template for a single row, then cloning it repeatedly:

var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.appendChild(tbody);
// Make a template row once up front
var rowtemplate = document.createElement('tr');
for(var j=0;j<50;j++){
    var td = document.createElement('td');
    td.style.backgroundColor="#a"+j%10+'c';
    tr.appendChild(td);
}
// Now clone it over and over instead of creating it piecemeal repeatedly
// Must pass true to ensure it clones whole tree, not just top level tr
for(var i = 0; i<3000;i++){
    table.appendChild(rowtemplate.cloneNode(true));
}

Obviously, it depends on the browser internals whether this helps, but typically, the browser should be able to clone an existing node tree faster than manually creating each element from scratch.

分享给朋友:
您可能感兴趣的文章:
随机阅读: