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

时间:2019-02-21 01:46:20

标签: javascript node.js asynchronous

背景:我正在准备一些工作面试,并重温一些计算机科学基础知识。我正在实现几种遍历二进制排序树的算法,特别是按顺序遍历,并且使用同步函数,promise和async / await关键字就可以做到这一点。

对于另一套实践,我认为将其移植到异步回调函数将是一个有用的挑战,特别是因为我正在采访Node.js职位。但是我绝对会坚持下去,尽管我最好继续研究其他主题,但这种失败一直困扰着我,我一直在转动方向盘!

因此,这是对经典算法问题的一种有趣而具有挑战性的转折,而不是出于胆小!

数据因此,假设您获得了一组对象,每个对象代表一个节点。一个节点必须具有value以及可选的leftright属性,这些属性与数组中另一个节点的索引号相对应。像这样:

[
   {"value":"root","left":1,"right":2},
   {"value":"L1","right":3},
   {"value":"R1"},
   {"value":"R2"}
]

如果将其绘制为二叉树,则它看起来像:

     root
     /   \
    /     \
   L1      R1
    \
     \
     R2

并实现顺序遍历,这些值应显示为“ L1,R2,根,R1”。

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

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;
}

对于基于promise的解决方案,我使我的助手函数返回一个promise对象,而不只是返回值,而且由于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)
      }
    });
  });

}

0 个答案:

没有答案