Javascript 高性能dom添加和删除

Javascript 高性能dom添加和删除,javascript,jquery,performance,dom,Javascript,Jquery,Performance,Dom,旁注:我使用的是JQuery,但不是任何第三方表组件(目前也不能) 我的问题是,我应该能够显示大量(10000条)经过的消息——每秒都会有数百条新消息,它们应该添加到底部。当我们达到10000条限制时,旧消息将从一开始就被删除 还应该可以过滤这些消息,因此当用户在搜索框中键入内容时,只会显示包含单词的行 网站结构很简单: <div id="message_container"> <p>Message 1</p> <p>Message 2<

旁注:我使用的是JQuery,但不是任何第三方表组件(目前也不能)

我的问题是,我应该能够显示大量(10000条)经过的消息——每秒都会有数百条新消息,它们应该添加到底部。当我们达到10000条限制时,旧消息将从一开始就被删除

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

网站结构很简单:

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

信息1

信息2

信息3

信息4

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

var newMessagesHtml = [];
// messages = new messages
for(var ii = 0; ii < messages.length; ii ++) {
   newMessagesHtml.push("<p>Message</p>");
}
$("#message_container").append(newMessagesHtml.join(''));
var newMessagesHtml=[];
//消息=新消息
对于(var ii=0;ii”;
}
$(“#消息_容器”).append(newMessagesHtml.join(“”));
我认为这不是问题(我缓存了message_容器的查询)。然而,当我们达到10000条限制并开始从顶部删除旧消息时,这是很慢的。应该怎么做?我尝试使用jquery过滤n条第一条消息并将其删除,但浏览器开始变得无响应。一次删除多条消息更好,还是一次删除一条消息更好

如果没有第三方组件(JQuery除外),您将如何实现这些功能? 1) 每秒添加和删除许多元素 2) 过滤掉我们不想看到的元素

感谢所有的帮助和想法。

选项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);
}
备选案文2:


你可以试试。它管理一个虚拟DOM并最小化对真实DOM的更新(这是一个瓶颈)。

对于一个实际的半实现,您可以尝试这样做。我在上面添加了@josdejong的提示,以便能够顺利地添加/删除/搜索

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

添加时添加dom元素,删除时再次删除dom元素,搜索仅切换css类(删除父dom节点)

示例可在此处找到:

查询列表的代码

;(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);
;(函数($){
函数QueryItem(parentElement,value){
this.parentElement=parentElement;
这个值=值;
this.element=未定义;
}
函数查询列表(元素、选项){
var=这个;
此参数为.items=[];
this.currentQuery=未定义;
this.suspendLayout=函数(){
元素。_oldNode=element.parentNode;
element.parentNode.removeChild(元素);
};
this.resumeLayout=函数(){
元素。\u oldNode.appendChild(元素);
};
this.add=函数(项){
var p,qry=新查询项(元素,项目);
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=元素;
qry.parentElement.appendChild(p);
本.项目.推送(qry);
if(this.items.length>options.maxItems){
this.remove(0,this.items.length-options.maxItems);
}
}
this.remove=函数(索引、长度){
变量i,项目,len;
对于(i=0,len=length | | 1;i
并作为试验的主要方法

$(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);
    });
});
$(函数(){
变量queryList=$('#msgContainer')。queryList({
最大项数:10000
}),指数=0,i,区间;
添加('hi there');
对于(i=0;i<7000;i++){
queryList.add('item'+i);
}
日志(queryList.items);
$(“#按钮搜索”)。在('click',函数(e){
var svalue=$('#inputSearch').val();
查询列表搜索(svalue);
});
间隔=设置间隔(函数(){
suspendLayout();
对于(变量i=0;i<100;i++){
add('附加消息'+((索引*100)+i));
}
queryList.resumeLayout();
索引++;
}, 1000);
$('#buttonStopInterval')。在('click',函数(e)上{
间隔时间;
});
});

哦,我刚刚尝试从dom中删除容器以附加节点,但这不会使现有消息从浏览器中消失吗?没有意识到。不,如果你在最后一个容器中再附加一个容器。在执行大量DOM操作时,它可以更快,但也可以更慢。你必须测试它是否能提高体育成绩
$(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);
    });
});