JSFiddle - React, Tailwind, and code Playground
JavaScript
///////////////////////// Async data API for testing //////////////////////////////////
var data = [{id:1,parent:0},{id:2,parent:1},{id:3,parent:0},{id:4,parent:3},{id:5,parent:4}];
function asyncReadRoot() {
return new Promise(function (accept, reject) {
setTimeout(function () {
accept(data.filter(function(e){return e.parent===0}));
},Math.random()*1000);
})
}
function asyncGetByParentId(parentId) {
return new Promise(function (accept, reject) {
setTimeout(function () {
accept(data.filter(function(e){return e.parent===parentId}));
},Math.random()*1000);
})
}
/////////////////////// Recursive Promises ///////////////////////
function read(result, root) {
return new Promise(function (accept, reject) {
if(!root) {
asyncReadRoot().then(function (arr) {
var childrenTasks = [];
arr.forEach(function (e) {
result[e.id] = e;
result[e.id].children = [];
childrenTasks.push(read(result[e.id], e.id));
});
Promise.all(childrenTasks).then((data) => {
// result already updated
accept(result);
});
});
} else {
asyncGetByParentId(root).then(function (children) {
if(children.length>0) {
var childrenTasks = [];
children.forEach(function (child) {
child.children = [];
result.children.push(child);
childrenTasks.push(read(child, child.id));
});
Promise.all(childrenTasks).then(function (data) {
// Children already updated, nothing to do except waiting for all results
accept(result);
});
} else {
accept();
}
});
}
});
}
var res = {};
read(res).then(function (data) {
console.log(JSON.stringify(res, null, " "));
});