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

What is a sensible way to structure my control flow (promises and looping)?

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

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

到目前为止,我已经通过以下代码实现了这一点:

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 promises)在 运行ning 一段时间后可能会导致堆栈问题。

我想做的是将其重组为:

  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());

非常感谢您的想法和建议!

什么堆栈问题?只要 getNextTaskRunner 是真正异步的(即它在某些时候将控制权交还给主循环,例如,如果它执行异步 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);
}