Doubts about the performance of DOM deletion

here is a chat box, and then insert chat data in real time, the process is roughly as follows:

// .
function appendMsg () {
    var newMsg = "<some-html-string></some-html-string>";
    $chatList.append(newMsg);  // jQuery Function.
}

then we limit the number of chat boxes to 100 at most:

// ,  100 .
function appendMsg () {
    var newMsg = "<some-html-string></some-html-string>";
    $chatList.children().length > 100 && $chatList.children().first().remove();
    $chatList.append(newMsg);
}

looks like OK, but when there are more users (20000 +) and chat areas are frantically brushed up, browser performance will decline significantly. Using Chrome developer tools for analysis, the number of Nodes in Timeline increases linearly, but the total memory usage remains within a fixed range. The cliff icon of JS Heap also indicates that the GC process is normal.

there is a question at this time: $(.). Remove () / removeChild () Why does the Nodes in the developer"s tools still rise and cause a significant decline in browser performance, but the memory is still normally reclaimed after the nodes are removed?

after trying several optimizations, the effect does not improve much. Later, I try to change the operation logic of node restrictions: take out the first chat item node when it exceeds 100. modify the HTML and then put it back to the chat list . The code is roughly as follows:

// ,  100 .
function appendMsg () {
    var newMsg = "<some-html-string></some-html-string>";
    if ($chatList.children().length > 100) {
        var $firstMsg = $chatList.children().first();
        $firstMsg.remove().html(newMsg);
        $chatList.append($firstMsg);
    } else {
        $chatList.append(newMsg);
    }
}

after using the above strategy, the performance problem disappears, and the Nodes curve in Timeline in the Chrome developer tool behaves the same as JS Heap , that is, it will be recycled after a period of time, then rise again, and then be recycled again.

is deeply confused and has a completely different result. Is it because the node of the latter append is taken from the page instead of a new variable? Is it because the memory of the former is not recycled? But the developer tool indicates that memory has been recycled; is it because the latter"s Nodes has been correctly recycled? But aren"t both common remove operations, why is the former soaring? What exactly does this Nodes stand for? But unfortunately, after searching a lot of content on the explosive stack, we couldn"t find any clear content related to "GC behavior after the removal of Nodes and Dom". Most of them are vague, perhaps because of the wrong posture ("; ; `)

in addition, about this Nodes :

var parent = document.getElementById("parent");
setInterval(function () {
    var div = document.createElement("div");
    div.innerHTML = "papapa";
    parent.children.length > 100 && parent.removeChild(parent.children[0]);
    parent.appendChild(div);
}, 10);

A page with such a simple timer should have 100 nodes, but the number of Nodes in developer tools remains at 200 + all the time. so what exactly is this Nodes ("_ `)

the writing is quite confusing. If anyone can give me some advice, I would appreciate it. (please)

Update:
has been instructed by two people to take a brief look at the part of the code about remove in jQuery. It may not be understood correctly, and please give me more advice.
remove part of the code is roughly as follows:

jQuery.fn.extend({
    //...
    remove: function( selector ) {
        return remove( this, selector );
    }
});

// Remove .
function remove( elem, selector, keepData ) {
    var node,
        nodes = selector ? jQuery.filter( selector, elem ) : elem,
        i = 0;

    for ( ; ( node = nodes[ i ] ) != null; iPP ) {
        if ( !keepData && node.nodeType === 1 ) {
            jQuery.cleanData( getAll( node ) );  // :.
        }

        if ( node.parentNode ) {
            if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
                setGlobalEval( getAll( node, "script" ) );  // .
            }
            node.parentNode.removeChild( node );  // : removeChild .
        }
    }

    return elem;  // .
}

// clearData .
cleanData: function( elems ) {
        var data, elem, type,
            special = jQuery.event.special,
            i = 0;

        for ( ; ( elem = elems[ i ] ) !== undefined; iPP ) {
            if ( acceptData( elem ) ) {
                if ( ( data = elem[ dataPriv.expando ] ) ) {
                    if ( data.events ) {
                        for ( type in data.events ) {
                            if ( special[ type ] ) {
                                jQuery.event.remove( elem, type );

                            // This is a shortcut to avoid jQuery.event.remove"s overhead
                            } else {
                                jQuery.removeEvent( elem, type, data.handle );
                            }
                        }
                    }

                    // Support: Chrome <= 35-45+
                    // Assign undefined instead of using delete, see Data-sharpremove
                    elem[ dataPriv.expando ] = undefined;
                }
                if ( elem[ dataUser.expando ] ) {

                    // Support: Chrome <= 35-45+
                    // Assign undefined instead of using delete, see Data-sharpremove
                    elem[ dataUser.expando ] = undefined;
                }
            }
        }
    }

so it does seem that after calling remove () , it only removes the Dom node and clears the Dom information. As for what jQuery does at other stages (such as caching or other behavior), it is indeed possible that the node is not released.

I will take the time to check it again, thank you

Jan.21,2022

I think there should be at least one thing to note:

$chatList.children().length > 100 && $chatList.children().first().remove();
$chatList.append(newMsg);

this code takes the first node out, removes it from the node tree, and generates a new node object to add to the node tree, so a new Node object is created here, which itself takes time. And the garbage collection mechanism checks the node that was deleted, and if it is indeed not referenced by other variables, it will be reclaimed. If it is still referenced by other variables (especially if you need to pay attention to the variable references in the closure), the node will not be recycled, which will cause the resource to be consumed all the time but not recycled.

if ($chatList.children().length > 100) {
    var $firstMsg = $chatList.children().first();
    $firstMsg.remove().html(newMsg);
    $chatList.append($firstMsg);
} else {
    $chatList.append(newMsg);
}

in this code, if 100 nodes have been generated, the first node object is removed from the node tree, but the object itself is reused, no new node objects are generated, and no node objects are deleted. Node resources are maintained at 100.


is there a bound event handler on each message record?

when you remove an element with an event handler from a document, it is highly likely that the event handler that was originally added to the element will not be treated as garbage collection. Keeping the
outdated "empty event handlers" in memory is the main cause of memory and performance problems in Web applications.


has encountered this problem in the past two days. Is there any good solution to this problem besides object reuse? thank you

.
Menu