【问题标题】:Complicated decision tree using js promises使用 js 承诺的复杂决策树
【发布时间】:2020-01-22 03:32:15
【问题描述】:

我正在尝试在使用 javascript Promise 时考虑格式化复杂决策树代码的最佳方式。

我已阅读以下问题,但找不到我要查找的内容:

我的愿望:

  1. 对于未来将进入项目的新开发人员来说,流程必须非常容易理解。
  2. 每个操作/步骤都将在一个独立的函数/承诺中处理,并且可以轻松替换,无需再次测试其他步骤。
  3. 输入应该从每个承诺流向下一个承诺。

例如一个简单的决策树:

我想到了以下方法:

方法一

var path = "";
var input = {hhh:111};

step_1(input)
  .then(step_2)
  .then(change_path_to_A_or_B_according_to_input)

    .then(step_a1)
    .then(step_a2)
    .then(change_path_to_X_or_Z_according_to_input)

      .then(step_x1)
      .then(step_x2)

      .then(step_z1)

    .then(step_b1)
    .then(step_b2)
    .then(step_b3);

在此方法中,每个步骤或连接将首先检查路径变量,然后决定是否应该运行。 改变路径相对困难,因为步骤的内容应该根据它们在决策树中的位置而改变(即应该调整路径变量的检查)。 但是,通过查看决策树很容易理解它,尽管缩进是手动的并且实际上没有任何效果。

方法二

var input = {hhh:111};

step_1(input)
  .then(step_2)
  .then((input) => {
    if(condition) {
      return
        step_a1(input)
          .then(step_a2)
          .then((input) => {
            if(condition) {
              return
                step_x1(input)
                  .then(step_x2);
            } else {
              return
                step_z1(input);
            }
          });
    } else {
      return
        step_b1(input)
          .then(step_b2)
          .then(step_b3);
    }
  });

在这种方法中,改变路径相对容易,因为只需要调整树本身。但是,它的可读性较差。

有更好的建议吗?

【问题讨论】:

  • 只需使用async/await,代码将等待每个 Promise 完成后再继续。这样您就可以使用简单的 if/else 代码而无需回调。
  • 首先,感谢您的建议。其次,您应该将您的建议添加为答案,而不是评论(我也要感谢代码示例)。第三,你的建议缺乏一些基本的 Promise 好处,比如对整个树的错误处理,所以我会先等待其他一些答案。
  • 我很少在这里发布实际答案,因为 95% 的 JS 问题都是重复的,人们简单地找不到答案,因为他们正在寻找错误的东西(或根本没有)。您使用决策树的事实在这里无关紧要。关键概念是如何在继续之前等待承诺,从而编写“同步”代码。这就是两年前或任何时候将 async/await 添加到 JS 的全部原因。这是包含错误处理的工作代码:jsfiddle.net/khrismuc/wzj0a6f8
  • 嘿伙计,好东西,我会做进一步的测试,但看起来你已经解决了。重复问题的答案让您投反对票?如果您将其添加为答案 - 我会将其标记为答案...
  • 为这个特定的工作构建一种专门的语言应该相当简单 - for example。这种事情的问题在于:(a) 它可能过于专业化——即它可能不允许所有未来的可能性。 (b) 这是你和其他人需要学习的新东西。在它的辩护中,这个例子很容易学习,并且允许你通过链接标准.then()和/或catch()在必要时“突破”,因为chain()chain().branch()都返回Promise .

标签: javascript promise decision-tree


【解决方案1】:

方法1是线性promise链,它的缩进是任意的,不一定与你的内部控制流有关。

方法 2 是正确的方法 - 这就是您在承诺链中执行条件的方式。为了更好的可读性,请使用不同的缩进样式和三元运算符

step_1({hhh:111})
.then(step_2)
.then(input => condition
  ? step_a1(input)
    .then(step_a2)
    .then(input => condition
      ? step_x1(input)
        .then(step_x2)
      : step_z1(input)
    )
  : step_b1(input)
    .then(step_b2)
    .then(step_b3);
);

或使用async/await语法:

var input = {hhh:111};
input = await step_1(input);
input = await step_2(input);
if (condition) {
    input = await step_a1(input);
    input = await step_a2(input);
    if (condition) {
        input = await step_x1(input);
        input = await step_x2(input);
    } else {
        input = await step_z1(input);
    }
} else {
    input = await step_b1(input);
    input = await step_b2(input);
    input = await step_b3(input);
}

【讨论】:

  • 这个input = await step_b3(input);可以缩短吗?我想到了这个:javascript function doStep(step) { step(input); // input is global var, accessible from any location } 有没有更好的办法?
  • @A-S,看起来@Bergi 在这里正确理解了您的要求,但没有解决一个方面(无论是在问题中还是在答案中);即决定a/bx/z是否可以/应该在promise链构建时做出,或者它们是否可以/应该在链结算时做出。这两种情况下的代码会有很大的不同。让您知道。
  • @A-S,如果不写答案,我无法给出正确的例子,但是这里有一些应该有所帮助的东西......
  • (1) 如果可以在构建承诺链时做出决定,您最终将得到以编程方式创建链的代码,以给出反映通过树的特定路径的表达式,例如 @ 987654329@;因此,通过树的路径在它开始稳定之前就已经固定了。
  • (2) 如果只能在链条稳定时才能做出决定,那么您最终会得到像 Bergi 在他的回答中给您的东西;链反映了通过树的所有可能路径,但所采用的特定路径是在链建立时决定的。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 2016-11-23
  • 2011-06-26
  • 2016-05-25
  • 2017-09-23
相关资源
最近更新 更多