【问题标题】:Conditional expanding observable chain条件扩展可观察链
【发布时间】:2020-01-01 19:02:23
【问题描述】:

问题:

我有多个条件要检查。其中一些会产生相同的 observable。

流程如下:

  1. 我检查表单是否保存在本地
  2. 如果是,则显示用户文本 1
  3. 如果不是,则检查服务器是否在 DB 中有此表单
  4. 如果服务器有,那么我显示文本 2
  5. 如果不显示文本 1

有没有办法避免导致相同结果但被复制粘贴的多个条件?

现在是这个样子

iif(
  () => this.savedLocally,
  this.showText1(),
  this.checkOnServer().pipe(
    switchMap(onServer => iif(
      () => onServer,
      this.showText2(),
      this.showText1()
    ))
  )
)

如果还有一个条件,那么它就多了一个级别,在某处重复this.showText1()

我正在寻找的是重新设计这个逻辑以减少重复。

诀窍是我需要执行三个检查(下一个仅在前一个具有预期结果时执行)并且所有这些都是异步的。

如果它很简单 if 我会使用 if (cond1 && cond2 && cond3) 但这里没那么简单。我有严格的检查顺序,每次检查都取决于之前的结果。

【问题讨论】:

  • 我认为没有比这更干净的了。还有其他方法可以在不重复 this.showText1() 的情况下做到这一点,但它们最终都会变得更冗长且可读性更低。
  • 我会发布一个答案。这将是一个很长的:)
  • @Reactgular 期待 :)

标签: angular typescript rxjs


【解决方案1】:

你绝对需要使用 observables 吗?看起来你可以用一个简单的异步函数更干净地写这个

async () => {
    if(this.savedLocally) return this.showText1();

    const isOnServer = await this.checkOnServer();
    if(isOnserver) return this.showText2();

    const isAnotherCondition = await this.checkAnotherCondition();
    if(isAnotherCondition ) return this.showText3();

    return this.showText1();
}

【讨论】:

  • 是的,我需要,因为我最初在我的 Angular 项目中使用它们,并且在 Observables 和 Promises 之间来回切换似乎不是一个好主意。
  • 啊,在这种情况下,我很抱歉我不能提供更多帮助。希望你能找到你想要的答案!
【解决方案2】:

您正在描述一组可观察对象,其中每个可观察对象决定是否应使用下一个可观察对象。

如果 observable 的值不满足条件,则使用下一个 observable 的值,直到到达集合的末尾,但如果 observable 满足条件,则不需要任何剩余的可观察的。

当 observable 完成时,你需要条件的积累。

您想要一些可扩展的东西。允许您异步解决一长串条件,但在不需要其他逻辑时停止。

您可以使用high-order observablereducers 和状态对象的组合。

高阶可观察对象是发出可观察对象的可观察对象。例如;

const higherOrder$ = of(of(true));

让我们使用一个状态对象来保存满足条件和值的累积。

interface State {
   // continue when value is false
   satisfy: boolean;
   // accumulation of data
   values: {[key:string]: any};
}

让我们从一个默认状态值开始。

const DEFAULT_STATE = {
   satisfy: false,
   values: {
      savedLocally: false,
      onServer: false
   }
};

让我们定义我们的 observables,它会发出将被累积的值。

  • 每个 observable 都会发出 satisfyvalues
  • 只要 satisfyfalse,就会使用下一个 observable。
  • 每个values都会累加到最终结果中。
const savedLocally$ = this.http.get(...).pipe(map(resp => ({
    satisfy: Boolean(resp), values: {savedLocally: resp}
})));

const checkOnServer$ = this.http.get(...).pipe(map(resp => ({
    satisfy: Boolean(resp), values: {onServer: resp}
})));

我们可以创建一个高阶可观察对象,切换到每个可观察对象,累积结果并停止在第一个满足的值上。

这里我使用scan() 运算符来累积每个发出值的值。

of(savedLocally$, checkOnServer$).pipe(
   switchMap(ob$ => ob$),
   scan((acc, next) => ({
      satisfy: next.satisfy,
      values: {...acc.values, ...next.values}
   }), DEFAULT_STATE),
   filter(state => state.satisfy),
   first(),
   map(state => state.values)
).subscribe(values => console.log(values));

现在我不知道这是否比您现在拥有的更简单,但它确实可以扩展以支持很长的可观察对象集合。

在此示例中,switchMap() 无权访问 previous 状态值。可以做,但是比较复杂,需要时间想想怎么做。

【讨论】:

  • 我做了一个小的测试样本来测试你的解决方案,因为对我来说它似乎只执行了最后一个可观察到的,因为of 一个接一个地发出所有值并且switchMap 发生变化主动订阅。 stackblitz.com/edit/rxjs-q6vieb?devtoolsheight=60 这里可以在控制台中观察到,其中2 被打印,同时1 必须是(在需要的逻辑中)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多