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");
});