从异步递归函数返回值

时间:2014-03-24 07:25:12

标签: node.js asynchronous recursion

我在Node.js中有一个复杂的递归函数,为了这个问题,我将其简化为以下内容:

function sum(tree) {
    if (!tree) return 0;
    var sumLeft = sum(tree.left);
    var sumRight = sum(tree.right);
    return sumLeft + tree.val + sumRight;
}

var exampleTree = {
    val: 3,
    right: { val: 4 },
    left: { val: 5, 
        right: {val: 6},
        left: {val: 7}
    }
}

console.log(sum(exampleTree)); // returns 25 = 3+4+5+6+7

现在我要转换功能" sum"到异步函数:

function sumAsync(tree, callback) {
    // ???
}

但是,由于函数现在没有返回值,我不知道如何获取值sumRight和sumLeft并将它们组合起来。

一种可能的选择是完全重写算法,使其迭代而不是递归(如本问题所示:how to make this synchronous recursive function asynchronous)。但是,在许多情况下,这可能非常复杂,并使整个程序不可读。有没有一种解决方案可以保持递归函数的简单结构,同时使其异步?

注意:我的问题不是对树中的值求和... ...树和函数只是一个最小工作示例。

编辑:根据vkurchatkin的回答和评论,我决定使用async.parallel。这是结果:

var async = require("async");


function sumAsync (tree, callback) {
    if (!tree) return setImmediate(callback.bind(null, null, 0));

    async.parallel([
      sumAsync.bind(this, tree.left),
      sumAsync.bind(this, tree.right),
    ],
    function(err, results) {
        callback(err, tree.val+results[0]+results[1]);
    });
}

sumAsync(exampleTree, function(err, result) {
    console.log(result);  // prints 25
});

2 个答案:

答案 0 :(得分:1)

这样的事可能有用:

function sumAsync (tree, callback) {
    if (!tree) return setImmediate(callback.bind(null, null, 0));

    var pending = 3;
    var sum = 0;
    var done = false;

    function handleError (err) {
       if (!done) {
          callback(err);
          done = true;
        }
    }

    function _callback (err, res) {
      if (err) return handleError(err);

      sum += res;

      if (!--pending && !done) {
        done = true;
        callback(null, sum);
      }
    }

    tree.fetchLeft(function (err, left) {
      if (err) return handleError(err);

      sumAsync(left, _callback);
    });

    tree.fetchRight(function (err, right) {
      if (err) return handleError(err);

      sumAsync(right, _callback);
    });

    tree.fetchValue(_callback);
}

它可能看起来很复杂,但它实际上只是一个临时的async.parallel实现,所以你可以改用它。

答案 1 :(得分:0)

假设树结构从一开始就存在,而不是一块一块地取出(我认为这是一种非常糟糕的做法)。

var exampleTree = {
    val: 3,
    right: { val: 4 },
    left: { val: 5, 
        right: {val: 6},
        left: {val: 7}
    }
}

function sum(tree,callback){
 if(!tree){ 
  if(callback!==undefined){ return callback(0); }
  return 0;
 }
 var sumLeft=sum(tree.left);
 var sumRight=sum(tree.right);
 var v = sumLeft+tree.val+sumRight;

 // callback is **not** passed so we continue
 if(callback===undefined){
  return v;
 }else{ // callback is passed meaning this is the root, end this.
  return callback(v);
 }
};

sum(null,function(result){
  console.log(result); // logs 0
});

sum(exampleTree,function(result){
    console.log(result); // logs 25
});

console.log(sum(exampleTree)); // logs 25