Rxjs: flatMap 中的 Subject 属性,避免意外触发

Rxjs: proper of Subject inside flatMap to avoid unexpected triggering

我有一个 Angular "Quiz" 应用程序并使用 rxjs 5.5.2 来实现具有某些业务逻辑的服务。我的 rxjs 流程出现问题,导致多次意外执行函数。

重现步骤:

  1. 调用 startNewQuiz 将新测验设置为活动
  2. 多次调用 answerQuestion 来回答测验问题。每个答案都会触发构造函数中定义的流程
  3. 再次调用startNewQuiz开始另一个测验

问题是在第 3 步调用 startNewQuiz 会多次触发 doStuffWithQuiz。调试显示这是因为 this.activeQuiz$ 在第 3 步发出一个值并触发 doStuffWithQuiz。由于我在第 2 步之前多次调用 answerQuestion - doStuffWithQuiz 也调用了多次。在流程中使用 activeQuiz$ 的唯一原因是获取当前测验并将其进一步传递给管道。

我希望我的 answerQuestionSubject 流程仅在我向 answerQuestionSubject 推送内容时执行,并避免触发 doStuffWithQuiz 当有东西被推送到 activeQuiz$.

那我怎样才能完成呢?

export class QuizFlowService {

  // to keep current active quiz
  private activeQuiz$ = new ReplaySubject<Quiz>(1);

  private answerQuestionSubject = new Subject<Answer>();

  ....

  constructor() {
    // setup flow for answers
    this.answerQuestionSubject.pipe(
      flatMap(
          // this is just to get active quiz and pass it futher
          () => this.activeQuiz$
      ),
      flatMap((quiz) => {
        // it is called multiple time on step 3
        doStuffWithQuiz(quiz)
      })
    ).subscribe();
  }

  // starts new quiz
  startNewQuiz(quiz: Quiz) {
    this.activeQuiz$.next(quiz);
  }

  // triggers answer flow
  answerQuestion(answer: Answer) {
    this.answerQuestionSubject.next(answer);
  }
}

你应该在你的第一个 flatMap

中使用 first 运算符
flatMap(
    () => this.activeQuiz$.first()
)

由于 activeQuiz 是一个主题,它可以发出多次。 (第 3 步中发生了什么),但是您只关心获得活动测验(1 个值)。首先,您只会收听 1 value/emission.