递归地向树状结构中的每个节点添加属性并返回修改后的树 [英] Recursively add property to every node in a tree-like structure and return modified tree

查看:42
本文介绍了递归地向树状结构中的每个节点添加属性并返回修改后的树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于线程中的评论树,我有以下数据结构.此结构包含在单个对象中.

I have the following data structure for a tree of comments in a thread. This structure is contained inside a single object.

comment {
    id: 1,
    text: 'foo',
    children: [
        comment {
            id: 2,
            text: 'foo-child',
            children: []
        },
        comment {
            id: 3,
            text: 'foo-child-2',
            children: []
        }
    ]
},
comment {
    id: 4,
    text: 'bar',
    children: []
}

这是后端API提供的,没有问题.我想要做的是递归地探索这棵树,对于每个节点(根节点或子节点),我想执行 API 调用并获取一些额外的数据对于每个单个节点,添加一些额外的属性, 并返回整个树,并将新键添加到每个节点.

This is provided by a back-end API, there's no problem in that. What I want to do is recursively explore this tree and for each node (either root or child node) I want to perform an API call and get some extra data for every single node, slap in some extra properties, and return the entire tree with the new keys added to each node.

function expandVoteData(comments) {
    return new Promise((resolve, reject) => {
        let isAuth = Auth.isUserAuthenticated();
        // 'this' is the vote collection
        async.each(comments, (root, callback) => {
            // First get the vote data
            async.parallel({
                votedata: function(callback) {
                    axios.get('/api/comment/'+root.id+'/votes').then(votedata => {
                        callback(null, votedata.data);
                    });
                },
                uservote: function(callback) {
                    if(!isAuth) {
                        callback(null, undefined);
                    } else {
                        axios.get('/api/votes/comment/'+root.id+'/'+Auth.getToken(), { headers: Auth.getApiAuthHeader() }).then(uservote => {
                            callback(null, uservote.data); // Continue
                        });
                    }
                }
            }, function(error, data) {
                if(error) {
                    console.log('Error! ', error);
                } else {
                    // We got the uservote and the votedata for this root comment, now expand the object
                    root.canVote = isAuth;
                    root.totalVotes = data.votedata.total;
                    root.instance = 'comment';

                    if(data.uservote !== undefined) {
                        root.userVote = data.uservote;
                    }

                    if(root.children && root.children.length > 0) {
                        // Call this function again on this set of children
                        // How to "wrap up" this result into the current tree?
                        expandVoteData(root.children);
                    }
                    callback(); // Mark this iteration as complete
                }
            });
        }, () => {
            // Done iterating
            console.log(comments);
            resolve();
        });
    })
}

它的作用是:接受一个'comments'参数(它是整个树对象),创建一个promise,遍历每个叶节点,并在异步请求中执行相应的API调用.如果叶节点有任何子节点,则对每个子节点重复该函数.

What it does is: accept a 'comments' parameter (which is the entire tree object), create a promise, iterate through each leaf node, and perform the respective API calls in asynchronous requests. If the leaf node has any children, repeat the function with each child node.

这理论上在同步世界中可以完美运行,但我需要做的是在处理每个节点后获取新树以供进一步处理,作为单个对象,就像作为输入一样.事实上,我为树中的每个单独节点获得了多个控制台打印,证明代码在编写时工作......不过我不想要单独的打印,我想将整个结果集包装在一个对象中.理想情况下,函数应该这样调用:

This theoretically would work perfectly in a synchronous world, but what I do need to do is to get the new tree after every node has been processed for further processing, as a single object, just like it was as an input. In fact, I get multiple console prints for each individual node in the tree, evidencing that the code works as it's written... I don't want individual prints though, I want to wrap up the entire set of results in a single object. Ideally, the function should be called like this:

expandVoteData(comments).then(expanded => {
    // yay!
});

有关如何执行此操作的任何提示?先谢谢了.

Any tips on how to perform this? Thank you beforehand.

推荐答案

如果你把代码分成多个函数并使用很酷的 async/await 会更容易句法.首先定义一个异步函数来更新一个节点而不关心子节点:

It gets more easy if you seperate the code into multiple functions and use the cool async / await syntax. Furst define an async function that updates one node without caring for the children:

async function updateNode(node) {
 const [votedata, uservote] = await Promise.all([
   axios.get('/api/comment/'+root.id+'/votes'),
    axios.get('/api/votes/comment/'+root.id+'/'+Auth.getToken(), { headers: Auth.getApiAuthHeader() })
 ]);

 node.totalVotes = votedata.total;
 node.instance = 'comment';

 if(uservote)
   node.userVote = uservote;
}

递归地更新所有节点就像这样简单:

To update all nodes recursively its then as easy as:

async function updateNodeRecursively(node) {
  await updateNode(node);
  await Promise.all(node.children.map(updateNodeRecursively));
}

这篇关于递归地向树状结构中的每个节点添加属性并返回修改后的树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆