Recursive promises to create tree

痴心易碎 提交于 2020-01-07 05:28:07

问题


A tree api returns childrens when node element is passed to it.

I pass the root node first and then on the basis of the nodes returned I pass all of them back recursively, if they have hasChildren parameter true.

Is there a way to know when the function has finished creating the tree.

function recursivelyFetchChildren(id, selectedAsset, parentId){
    return ajaxCall(id, selectedAsset, parentId)
    .then(function(data){
        //collects all childs in childs array
        childs.push(data);
        for(var i=0; i<data.length; i++){
            if(data[i].HasChildren){
                return recursivelyFetchChildren(id,selectedAsset,data[i].Id);
            }else{
                //this return statement prematurely completes the promise
                return data[i];
            }
        }
    });
}

recursivelyFetchChildren(id, selectedAsset, parentId).then(function(){
    print(childs)  //prints the childs before all the promises have resolved
});

Can anyone suggest an approach where I can make the recursivelyFetchChildren function wait for rendering the complete tree?


回答1:


Go the other way, and return a function that is resolved when all of its children are resolved.

{
  id: "123",
  data: {
    children: [
      { id: "234", value: 2, data: { children: [] } },
    ]
  }
}


const loadData = node => getData(`/url/${node.id}`).then(data => {
  return loadChildren(data.hasChildren ? data.children : [])
    .then(children => {
      data.children = children;
      node.data = data;
      return node;
    });
});
const loadChildren = children => Promise.all(children.map(loadData));

Because I am returning and chaining promises, the outermost one that I return won't resolve, until the inner-most one is finished.

Personally, I would be likely to build a new node, rather than modify the one that I had, but that's a different matter altogether.

EDIT

Mutual Recursion: two functions that call one another.

function a () { return b(); }
function b () { return a(); }

If you have a tree where each root has an array of children, then you can write two functions to bounce back and forth between one another: one to deal with a node, one to deal with an array of nodes. There are other examples, of course, but one is going to be the recursive function you want, and the other is going to be a loop, or something that lets you call the recursive function on one thing at a time... usually; again, there are other cases.

const tree = {
  value: 1,
  children: [{
    value: 2,
    children: []
  }, {
    value: 3,
    children: []
  }]
};

const sumChildren = children =>
  children
    .map(sumNode)
    .reduce((x, y) => x + y, 0);

const sumNode = node =>
  node.value + sumChildren(node.children);

const total = sumNode(tree); // 6

Promise Resolution

One of the things that's usually missed, in terms of promises, is that you can return a promise, inside of a .then and cause the resolution of the promise to wait longer. When it resolves, it will have the value that b resolved with (or the error that b had)

eventuallyGetA()
  .then(a => eventuallyGetB(a.data))
  .then(b => console.log(`I waited for ${b}`));

You can even do something like

const wait = ms =>
  new Promise(resolve => setTimeout(resolve, ms));

doX()
  .then(() => wait(2000))
  .then(doY)
  .then(() => wait(3000))
  .then(doZ);

It should be pretty straightforward as to what that sequence is going to do.

Hope that helps.



来源:https://stackoverflow.com/questions/43601414/recursive-promises-to-create-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!