RxJS乐观更新(强制发出乐观值)

时间:2020-02-28 08:28:27

标签: javascript rxjs

您将如何在RxJS中实现乐观更新?参见以下示例:

const todoIdSource: Subject<string> = new Subject();
const $todo = todoIdSource.pipe(
    tap(id => {
        const optimisticTodo: any = {
            userId: 1,
            id: id, // Use some value from the source observable
            title: "delectus aut autem",
            completed: false
        };
        // TODO force emit optimisticTodo! How? :)
    }),
    concatMap((id) => ajax('https://jsonplaceholder.typicode.com/todos/' + id)),
    map(response => response.response)
);

$todo.subscribe(value => console.log('TODO', value));

todoIdSource.next('1');

$todo在ajax调用完成之前不会发出。 但是我希望它在todoIdSource发出后立即发出乐观值。 最后,$ todo应该发出2个值:

  • 乐观价值
  • ajax结果的值

注意:

  • 乐观值不应触发ajax调用。
  • 乐观值应该能够使用可观察到的todoIdSource来源的数据。

在RxJS中是否有一种优雅的方法来实现这一目标?我可以想象引入第二个Observable optimisticTodo$,然后将其与$todo合并。但这并不优雅:)

2 个答案:

答案 0 :(得分:3)

要么

concatMap(id =>
    from(ajax("https://jsonplaceholder.typicode.com/todos/" + id)).pipe(
      map(response => response.response),
      startWith({...})
    )
  )

请记住,startWith必须是最后一个运算符(或至少在map之后)。 这样可以确保传递给您的值不会被映射,在这种情况下,由于您使用映射来提取响应,因此不会被映射。

  concatMap(id =>
    merge(
      of({...}),
      from(ajax("https://jsonplaceholder.typicode.com/todos/" + id)).pipe(
        map(response => response.response)
      )
    )
  )

两者都能达成相同的目标:

每当todoIdSource发出时,立即发出乐观的todo,并在ajax调用结束时发出实际的todo。

我更喜欢startWith方法。

stackblitz

小附录:我假设订阅者实际上只对当前状态感兴趣。

您可以添加另一个

  scan((acc,todo) =>({...acc,...{[todo.id]:todo}}), {}),
  map(v => Object.keys(v).map(k => v[k])),

要实现该目标,请参见addendum stackblitz

答案 1 :(得分:1)

您可以使用startWith operator实现该行为。