构建我的控制流(承诺和循环)的合理方法是什么?

时间:2016-08-01 13:54:50

标签: node.js promise bluebird

我不确定如何使用promises / bluebird充分实现我想要的控制流程。

基本上我有一个存储了X'任务'的数据库,每个都需要按顺序加载和执行。我不希望同时运行多个任务,整个代码必须无限期地继续执行。

到目前为止,我已使用以下代码实现了此目的:

export default function syncLoop() {
  getNextTaskRunner().then((taskRunner) => {
    if (taskRunner) {
      taskRunner.startTask()
      .then(syncLoop)
      .catch((error) => {
        throw new Error(error);
      });
    } else {
      syncLoop();
    }
  });
}

getNextTaskRunner()只是从数据库中加载并解析下一个任务(根据时间戳计算)。或者它以null结算(没有任务可用)。

当完整任务完成时,

taskRunner.startTask()将解析为null。

我被告知它的结构方式(递归/ w承诺)可能会在运行一段时间后导致堆栈问题。

我所想做的是将其重组为:

  let running = false;
  setInterval(() => {
    if (!running) {
      running = true;
      getNextTaskRunner().then((taskRunner) => {
        if (taskRunner) {
          taskRunner.startTask()
          .then(() => {
            running = false;
          })
          .catch((error) => {
            log.error(error);
          });
        } else {
          running = false;
        }
      });
    }
  }, 5000);

还是另一种可能性,使用某种形式的事件发射器?

task.on('complete', nextTask());

非常感谢您的意见和建议!

1 个答案:

答案 0 :(得分:1)

什么堆栈问题?只要getNextTaskRunner是真正的异步(即,它在某个时刻将控制权交还给主循环,例如,如果它执行async io),那么编写代码的方式就完全没问题了。在这种情况下,代码中没有递归。谁告诉你这是错误的。

虽然您可能希望在某处添加setTimeout,但您不会在请求时充斥数据库。此外,如果getNextTaskRunner不再同步(例如在内存缓存中),它会对您有所帮助:

export default function syncLoop() {
  setTimeout(() => {
    getNextTaskRunner().then((taskRunner) => {
      if (taskRunner) {
        taskRunner.startTask()
          .then(syncLoop)
          .catch((error) => {
            throw new Error(error);
          });
      } else {
        syncLoop();
      }
    });
  }, 2000);
}