0

Basically, I'm trying to set up a tree, where each node has a reference to it's parent. I've tried the following:

function insert_node(node_data, parent_id) {
  var deferral = Q.defer()
  deferral.promise.then(async_create_node(node_data, parent_id))

  deferral.promise.then(function(parent_node_id) {
    var deferral = Q.defer()
    node_data.children.forEach(function(node) {
      deferral.promise.then(insert_node(generate_node_data(node), parent_node_id))
    }
    return deferral.resolve();
  }

  return deferral.resolve();
}

function insert_all_nodes() {
  var deferral = Q.defer();
  deferral.promise.then(insert_node(top_node));
  deferral.resolve()
}

The issue is that I need it to only create one node at a time, and wait until that node is done being created, and only then move on to the next one. The way it's working now, it will start creating a new node before the first one is finished, which causes problems. I've tried nesting the functions in several ways, and using Q.fcall(). I need the id that async_create_node returns for multiple child nodes, otherwise I'd just use recursion.

CSturgess
  • 1,547
  • 2
  • 13
  • 29
  • Why is `parent_node_id` different from its corresponding `parent_id`? – Beetroot-Beetroot Jun 16 '13 at 06:40
  • Say node A has the child B, and B has children C, D, and E. insert_node is being called to create node B. Parent_id is the id of Node A. async_create_node returns the id or node B, which is then called parent_node_id. So parent_id is the id of node A, and parent_node_id is the id of node B. – CSturgess Jun 16 '13 at 06:49

1 Answers1

0

The combination of asynchronicity and recursion makes this slightly tricky to get one's mind round.

Firstly, we must be sure that async_create_node() returns a promise, otherwise there's no basis on which to acknowledge its asynchronicity and the whole enterprise would need to be synchronous.

Secondly, let's assume that, at each level (particularly the topmost level), we need to know not only that that level's node has been created but also that the whole tree below it has been created.

Then, you should be able to do something like this :

function insert_node(node_data, parent_id) {
    var dfrd = Q.defer();
    async_create_node(node_data, parent_id).then(function(id) {
        var promises = [];
        node_data.children.forEach(function(node) {
            promises.push(insert_node(generate_node_data(node), id));
        });
        Q.all(promises).then(dfrd.resolve);
    });
    return dfrd.promise;
}

function insert_all_nodes() {
    return insert_node(top_node_data, top_node_id);
}

That's all off the top of my head, untested.

EDIT

To create sibling nodes sequentially, you can build a .then() chain in the forEach loop as follows :

function insert_node(node_data, parent_id) {
    var dfrd = Q.defer();
    async_create_node(node_data, parent_id).then(function(id) {
        var p = Q.defer().resolve().promise;//Seed promise on which to build a then() chain.
        node_data.children.forEach(function(node) {
            p = p.then(function() {
                insert_node(generate_node_data(node), id);
            });
        });
        p.then(dfrd.resolve);
    });
    return dfrd.promise;
}
Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • I'll try to implement it now. – CSturgess Jun 16 '13 at 07:50
  • No, that doesn't seem to work. It calls insert_node in the forEach loop, meaning that multiple nodes are being created simultaneously. I'm not sure how to fix that, though. – CSturgess Jun 16 '13 at 08:24
  • Yes, as it stands sibling nodes will be created simultaneously. Maybe if you could explain why that's not possible. – Beetroot-Beetroot Jun 16 '13 at 08:26
  • I'm using mongoose, and when I try to implement a solution like this, it fails with a "VersionError: No matching document found". From what I can understand, this is caused when you try to update an array reference when there's been a change between getting the info and saving it. When a new node is added, the parent node is updated (automatically) to include a reference to the new child node. So when multiple nodes are added at once, the "child" array is opened several times, and only one of them goes through. – CSturgess Jun 16 '13 at 09:07
  • OK, I'm not sure I really understand the Mongoose issue but assuming it's just a question of adding sibling tree nodes sequentially, then my edit may do the job. – Beetroot-Beetroot Jun 16 '13 at 09:32