高性能dom添加和删除

时间:2014-12-14 15:07:52

标签: javascript jquery performance dom

旁注:我使用的是JQuery,但没有使用任何第三方表组件(我现在也不能)。

我的问题是我应该能够显示很多(10000)正在传递的消息 - 每秒会有数百条新消息,它们应该被添加到底部。当我们达到10000限制时,旧消息将从头开始删除。

还应该有可能过滤这些消息,因此当用户在搜索框中输入内容时,只会显示包含这些字词的行。

网站结构很简单:

<div id="message_container">
 <p>Message 1</p>
 <p>Message 2</p>
 <p>Message 3</p>
 <p>Message 4</p>
</div>

目前我一次添加多条消息,速度非常快:

var newMessagesHtml = [];
// messages = new messages
for(var ii = 0; ii < messages.length; ii ++) {
   newMessagesHtml.push("<p>Message</p>");
}
$("#message_container").append(newMessagesHtml.join(''));

我认为这不是问题(我缓存了message_container的查询)。但是,当我们达到10000限制并开始从顶部删除旧邮件时,这很慢。应该怎么做?我尝试使用jquery过滤n个第一条消息并将其删除,但浏览器开始变得无法响应。最好一次删除多条消息,还是一次删除多条消息?

除了JQuery之外,如果没有第三方组件,你会怎么做? 1)每秒添加和删除许多元素 2)过滤掉我们不想看到的元素

感谢所有的帮助和想法。

2 个答案:

答案 0 :(得分:3)

对于实际的半实现,你可以试试这个。我在上面的@Jos de Jong中添加了提示,以便顺利添加/删除/搜索

QueryList类增加了添加/删除消息的可能性,queryList.items包含实际项目列表,通过设置maxItems,您可以轻松配置要查看的项目数量:)

在添加时,添加dom元素,删除dom元素也会被删除,搜索只是切换css类(删除父dom节点)

可以在此处找到示例:http://jsfiddle.net/Icepickle/j4nLh9k1/

queryList的代码

;(function($) {
    function QueryItem(parentElement, value) {
        this.parentElement = parentElement;
        this.value = value;
        this.element = undefined;
    }

    function QueryList(element, options) {
        var that = this;
        this.items = [];
        this.currentQuery = undefined;

        this.suspendLayout = function() {
            element._oldNode = element.parentNode;
            element.parentNode.removeChild(element);
        };

        this.resumeLayout = function() {
            element._oldNode.appendChild(element);
        };

        this.add = function(item) {
            var p, qry = new QueryItem(element, item);
            var p = document.createElement('p');
            if (this.currentQuery && item.indexOf(this.currentQuery) === -1) {
                p.className = 'hidden';
            }
            p.innerHTML = qry.value;
            qry.element = p;
            qry.parentElement = element;
            qry.parentElement.appendChild(p);
            this.items.push(qry);
            if (this.items.length > options.maxItems) {
                this.remove(0, this.items.length - options.maxItems);
            }
        }

        this.remove = function(index, length) {
            var i, item, len;
            for (i = 0, len = length || 1; i < len; i++) {
                item = this.items[index];
                item.parentElement.removeChild(item.element);
                item.element = undefined;
            }
            this.items.splice(index, length);
        };

        this.search = function(txt) {
            var i, len, item;
            this.currentQuery = txt;
            this.suspendLayout();
            for (i = 0, len = this.items.length; i < len; i++) {
                item = this.items[i];
                if (txt && item.value.indexOf(txt) === -1) {
                    item.element.className = 'hidden';
                } else {
                    item.element.className = '';
                }
            }
            this.resumeLayout();
        };
    }

    $.fn.queryList = function(options) {
        if (typeof this.selector === 'undefined' || this.length !== 1) {
            throw 'QueryList has to be linked to exactly one item';
        }
        var qry = new QueryList(this[0], options);
        this.data('queryList', qry);
        return qry;
    };
})(jQuery);

并作为测试主要方法

$(function() {
    var queryList = $('#msgContainer').queryList({
        maxItems: 10000
    }), index = 0, i, interval;
    queryList.add('hi there');
    for (i = 0; i < 7000; i++) {
        queryList.add('item ' + i);
    }
    console.log(queryList.items);

    $('#buttonSearch').on('click', function(e) {
        var svalue = $('#inputSearch').val();
        queryList.search(svalue);
    });

    interval = setInterval(function() {
        queryList.suspendLayout();
        for (var i = 0; i < 100; i++) {
            queryList.add('Additional message ' + ((index * 100) + i));
        }
        queryList.resumeLayout();
        index++;
    }, 1000);

    $('#buttonStopInterval').on('click', function(e) {
        clearInterval(interval);
    });
});

答案 1 :(得分:1)

选项1:

不要使用jQuery或HTML字符串。而是将您的消息创建为DOM元素,并使用JavaScript调用追加/删除它们,例如:

var newMessagesHtml = [];
var container = document.getElementById('message_container');
for(var ii = 0; ii < messages.length; ii ++) {
   var msg = document.createElement('p');
   msg.appendChild(document.createTextNode(messages[i]));
   container.appendChild(msg);
}

如果您一次添加大量消息,可以从DOM中删除message_container元素,向其添加所有消息,然后再将其附加到DOM,如:

var container = document.getElementById('message_container');
var parent = container.parentNode;
parent.removeChild(container);

// ...append a lot of messages...

parent.appendChild(container);

选项2:

您可以尝试React。它管理虚拟DOM并最小化真实DOM上的更新(这是瓶颈)。