在JavaScript中使用异步回调调用递归函数

在JavaScript中使用异步回调调用递归函数,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,背景:我正在准备一些面试,复习一些计算机科学基础知识。我实现了几种用于遍历二进制排序树的算法,特别是顺序遍历,我能够使用同步函数以及Promission和async/await关键字很好地完成这项工作 对于一组额外的实践,我认为将其移植到异步回调函数将是一个有用的挑战,特别是因为我正在面试Node.js职位。但是我完全被它卡住了,虽然我最好还是继续学习其他的话题,但这次失败一直困扰着我,我一直在旋转我的轮子 因此,这是一个有趣的但挑战性的经典算法问题,而不是心脏微弱的问题!p> 数据因此,假设给

背景:我正在准备一些面试,复习一些计算机科学基础知识。我实现了几种用于遍历二进制排序树的算法,特别是顺序遍历,我能够使用同步函数以及Promission和async/await关键字很好地完成这项工作

对于一组额外的实践,我认为将其移植到异步回调函数将是一个有用的挑战,特别是因为我正在面试Node.js职位。但是我完全被它卡住了,虽然我最好还是继续学习其他的话题,但这次失败一直困扰着我,我一直在旋转我的轮子

因此,这是一个有趣的但挑战性的经典算法问题,而不是心脏微弱的问题!p> 数据因此,假设给你一个对象数组,每个对象代表一个节点。节点必须具有与数组中另一个节点的索引号相对应的
、可选的
属性。比如说:

[
   {"value":"root","left":1,"right":2},
   {"value":"L1","right":3},
   {"value":"R1"},
   {"value":"R2"}
]
如果将其绘制为二叉树,它看起来像:

     root
     /   \
    /     \
   L1      R1
    \
     \
     R2
并实现顺序遍历,值应显示为'L1,R2,root,R1'

在同步解决方案中,我编写了两个helper方法来获取根节点(假设数组的第一个元素始终是根)和另一个方法来查找特定索引处的节点。解决方案如下:

function SyncTree(data) {
    this.data = data;
};

SyncTree.prototype.getRoot = function () {
    return this.data[0];
};

SyncTree.prototype.getNode = function (index) {
    return this.data[index];
};

SyncTree.prototype.orderTree = function () {
  const results = [];

  const inorder = node => {
    if (node) {
      inorder(this.getNode(node.left));
      results.push(node.value);
      inorder(this.getNode(node.right));
    }
  }

  inorder(this.getRoot());
  return results;
}
对于基于承诺的解决方案,我让我的助手函数返回一个承诺对象,而不仅仅是值,而且我能够非常轻松地处理它,因为async/await使代码看起来是同步的

function PromiseTree(data) {
    if (!Array.isArray(data)) {
        throw new Error('The data must be an Array');
    }
    this.data = data;
};

PromiseTree.prototype.getRoot = function (callback) {
   return Promise.resolve(this.data[0]);
};

PromiseTree.prototype.getNode = function (index, callback) {
    return Promise.resolve(this.data[index]);
};

PromiseTree.prototype.orderTree = function () {
  const results = [];

  const inorder = async node => {
    if (node) {
      const left = await this.getNode(node.left);
      await inorder(left);
      results.push(node.value);
      const right = await this.getNode(node.right);
      await inorder(right);
    }
  }

  return this.getRoot().then(async root => {
    await inorder(root);
    return Promise.resolve(results);
  });
}
对于回调挑战,我编写了一些简单的逻辑,使其立即返回值或随机延迟。我知道在现实世界中,在这个用例中使用回调函数绝对是迟钝的,而同步方法将是首选,但我的头撞到了墙上,我被卡住了。到目前为止,这就是我得到的结果,但它返回的结果不一致,因为某些回调函数在其他回调函数之前启动

function CallbackTree(data) {
    if (!Array.isArray(data)) {
        throw new Error('The data must be an Array');
    }
    this.data = data;
};

function inconsistentCallback(value, callback) {
    if (Math.random() > 0.5) {
        setImmediate(function () {
            callback(null, value);
        });
    } else {
        callback(null, value);
    }

}

CallbackTree.prototype.getRoot = function (callback) {
    inconsistentCallback(this.data[0], callback);
};

CallbackTree.prototype.getNode = function (index, callback) {
    inconsistentCallback(this.data[index], callback);
};

CallbackTree.prototype.orderTree = function (callback) {
  const results = [];

  const inorder = (node, cb) => {
    if (node) {
      results.push(node.value)
      this.getNode(node.left, (err, left) => {
        this.getNode(node.right, (err, right) => {
          inorder(node.left, cb)
          inorder(node.right, cb)
          cb()
        })
      })
    }
  }

  this.getRoot((err, root) => {
    inorder(root, () => {
      if (results.length === this.data.length) {
        callback(null, results)
      }
    });
  });

}