在算法调用堆栈中管理同步和异步函数

Managing sync and async functions in an algorithm call stack

TLDR:如果 大多数 函数实际上不是 [=11],我必须通过复杂的调用堆栈使用 asyncawait =]?是否有其他编程模式?

上下文

这个问题可能更多地是关于设计模式和整体软件架构,而不是特定的语法问题。我正在 node.js 中编写一个相当复杂的算法。程序流程包括一个初始的异步调用来获取一些数据,然后移动到一系列基于数据的同步计算步骤。计算步骤是迭代的,随着它们的迭代,它们会产生结果。但有时,如果计算满足某些条件,则需要获取更多数据。这是图表形式的简化版本:

calcStep 循环同步运行数千次,推送结果。但偶尔它会回到 getData,程序必须等待更多数据进入,然后才能再次进入 calcStep 循环。

在代码中

上述代码的简化版本在 JS 代码中可能如下所示:

let data;

async function init() {
  data = await getData();
  processData();
  calcStep1();
}

function calcStep1() {
  // do some calculations
  calcStep2();
}

function calcStep2() {
  // do more calculations
  calcStep3();
}

function calcStep3() {
  // do more calculations
  pushToResults();

  if (some_condition) {
    getData(); // <------ question is here
  }

  if (stop_condition) {
    finish();
  } else {
    calcStep1();
  }
}

其中pushToResultsfinish也是简单的同步函数。我在这里写 calcStep 函数是分开的,因为在实际代码中,它们实际上是 class 方法,来自 class 基于关注点分离定义的方法。

问题

明显的问题出现了,如果满足some_condition,我需要等待获取更多数据才能继续calcStep循环,我需要在之前使用await关键字在 calcStep3 中调用 getData,这意味着 calcStep3 必须被调用 async,我们也必须 awaitcalcStep2 中调用,并且所有在链条上,即使是同步函数也必须标记为 asyncawaited.

在这个简化的示例中,这样做不会太令人反感。但实际上,我的算法要复杂得多,调用堆栈更深,涉及许多 class 方法、迭代等。在这种情况下,是否有更好的方法来管理 awaiting 函数?我可以使用的其他工具,如生成器或事件发射器?我愿意接受简单的解决方案或范式转变。

如果您不想创建函数 async 并将其传播到链中,请使用 .then()。您需要在 .then() 中复制以下代码;你可以通过把它放在它自己的函数中来简化它。

function maybeRepeat() {
  if (stop_condition) {
    finish();
  } else {
    calcStep1();
  }
}

function calcStep3() {
  // do more calculations
  pushToResults();

  if (some_condition) {
    getData().then(maybeRepeat);
  } else {
    maybeRepeat()
  }
}