JSFiddle - React, Tailwind, and code Playground

HTML

<ul id="root">
    <li>1</li>
    <li>
        2
        <ul>
            <li>2.1</li>
         </ul>
        <ul>
            <li>2.2</li>
        </ul>
        <ul>
            <li>2.3</li>
        </ul>
    </li>
    <li>3</li>
    <li>4</li>
    <li>
        5
        <ul>
            <li>
                5.1
                <ul>
                    <li>
                        5.1.1
                    </li>
                </ul>
            </li>
            <li>
                5.2
            </li>
        </ul>
    </li>
    <li>
         6   
    </li>
</ul>

CSS

ul {
    padding-left:2em;
    list-style: disc inside;
}

JavaScript

function processTree(rootNode, callback) {
    var i, l, pending;

    // If there are no child nodes, just invoke the callback
    // and return immediately
    if ((pending = rootNode.childNodes.length) === 0) {
        callback();
        return;
    }

    // Create a function to call, when something completes


    function done() {
        --pending || callback();
    }

    // For each child node
    for (i = 0, l = rootNode.childNodes.length; i < l; i++) {
        // Wrap the following to avoid the good ol'
        // index-closure-loop issue. Pass the function
        // a child node
        (function(node) {

            // Process the child node asynchronously
            processChildNodeAsync(node, function() {

                // When the processing is done, descend into
                // the child's tree (recurse)
                processTree(node, done);

            });

        }(rootNode.childNodes[i]));
    }
}

// ---------------------
// Example (fake) async function


function processChildNodeAsync(node, callback) {
    // Skip text/whitespace nodes
    if (node.nodeType === Node.TEXT_NODE) {
        callback();
        return;
    }
    setTimeout(function() {
        node.style.background = "green";
        callback();
    }, 200);
}

// ---------------------
// Kick it off
processTree(document.getElementById("root"), function() {
    alert("All done");
});