John1984 John1984 - 1 year ago 60
Javascript Question

Performance with jQuery .nextUntil on large DOM

I'm looking to address a performance issue I'm having with a very large DOM. In essence, this a word-processing style app inside the browser using


Suppose I have a structure like this:

<div class="header">...</div>
<div class="actor">...</div>
<div class="director">...</div>
<div class="producer">...</div>
<div class="writer">...</div>
<div class="executive">...</div>
<div class="studio">...</div>
<div class="footer">...</div>

I then have some code which ends up returning (for example):

<div class="writer">...</div>

as a jQuery object. I then need to retrieve all of this object's surrounding
as a selection and then further filter this list using a

Currently, I have the following code, which works correctly:

// Find header
var header_object = object.prevUntil(".header").last().prev();

// Select all objects between header and footer, and then filter
var object_list = header_object.nextUntil(".footer", ".actor");

// Iterate through object_list
// Run additional code on the objects

The only problem is that due to the app being a word processor of sorts, the DOM structure is often very large (e.g. over 5000 elements) and executing this code locks up the browser for an unacceptable amount of time (over 10 - 30 seconds).

As such, I'm looking for a way to customize the code I have to make it more efficient / improve performance.

I should also point out that the HTML structure above is not
(header - 5000 elements - footer)
, rather it is 200 x
(header - elements - footer)
. As such, each traversal operation is only maybe 25 elements from header to footer, but it has to run many times.

Any suggestions? Many thanks!

Answer Source

You could enhance performance by not using jQuery, and creating your own functions that are more specific to your use case.

function getClosest(el, klass, dir) {
    while (el && (!el.classList.contains(klass))) {
        el = el[dir ? 'previousElementSibling' : 'nextElementSibling'];
    return el;

function getbetween(from, to, filterKlass) {
    var list = [];
    while(from && to && from !== to) {
        if ((from = from.nextElementSibling) !== to) {
            filterKlass ? (from.classList.contains(filterKlass) ? list.push(from) : Infinity) : list.push(from);
    return list;

var object  = $('.writer');
var element = object.get(0);

var header_object = getClosest(element, 'header', true);
var footer_object = getClosest(element, 'footer', false);
var object_list   = getbetween(header_object, footer_object, 'actor');

object_list.forEach(function(element) {


Traversing the next element sibling directly, and checking for classes, should be much faster than using nextUntil