RxJS 6 /点击运算符何时发出值

Posted

技术标签:

【中文标题】RxJS 6 /点击运算符何时发出值【英文标题】:RxJS 6 / When does tap operator emit a value 【发布时间】:2019-04-16 09:25:44 【问题描述】:

我一直在想是否可以安全地假设在使用 tap 操作符之后,它内部的副作用已经完成。

我的用例是ngrx。

 ...
tap(() => 
    this.store.dispatch(new SetValue("Hello World"));
  
),
switchMap(() => this.store),
select(state => state.value),
tap(state => 
  if (state === undefined) 
    throw new Error("Couldn't find value");
  
)

SetValue是一个实现ngrx的类

export class SetValue implements Action 
  readonly type = SET_VALUE;
  constructor(public payload: string) 

我正在尝试实现的是在商店中设置一个值,然后检查它是否已有效设置。

我可以假设在点击操作符之后调度已经完成吗?

回答

我在 Angular Router guards 上使用它通过 url 上的参数设置初始状态,所以我最终过滤为仅在商店有新值时继续

 ...
tap(() => this.store.dispatch(new SetValue("Hello World"))),
switchMap(() => this.store),
select(state => state.value),
filter(value => value === "Hello World"),
take(1)

【问题讨论】:

我对我的代码的思考过于迫切,我对任何遇到此问题的人的建议是鼓励反应式编程,考虑蒸汽以及何时发送数据 【参考方案1】:

RxJS 中的大多数操作都是同步的,所以如果 this.store.dispatch(new SetValue("Hello World")) 不执行任何异步任务,它可能会按预期工作(它仍然只是一个主题)。

但是,您不应依赖此行为。 NgRx 可能会改变它的内部结构,通常最好不要依赖 RxJS 运算符的同步/异步(这在过去已经发生过,例如 from() 从 RxJS 4 到 RxJS 5)。

如果您想确保已设置某些内容,请更改您的 new SetValue("Hello World") 效果以在完成所需操作后发出另一个操作。

【讨论】:

SetValue 是一个实现来自ngrx的动作的类,你的建议如何适应? export class SetValue implements Action readonly type = SET_VALUE; constructor(public payload: string) 你可能会在另一个效果中处理这个动作,因为我猜你没有创建一个什么都不做的动作。因此,当它处理完 SetValue 动作后,您将其映射到另一个动作,告诉您 SetValue 已完成。 我正在将问题编辑为现实世界的问题。我正在尝试使用基于 url 的 RouteGuard 为商店提供值。那是动作调度的地方。我想检查商店中的值是否已成功填写,否则重定向到另一个页面 除了@martin 所说的,ngrx 也建议我们这样做。根据加载/设置操作发出成功/失败操作。然后,您可以收听由 Success/Fail 操作更新的加载/错误状态并决定离开。 为了完整起见,我最终在点击旁边过滤(rxjs 过滤器运算符),以确保商店更改了值。【参考方案2】:

tap 运算符接受 3 个参数。

1- 如果源 observable 发出一个值,tap 运算符的第一个参数是一个函数,该函数接收该发出的值作为参数。

2- 如果源 observable 进入错误状态,tap 运算符的第二个参数是一个接收该错误作为参数的函数。所以在这里你可以调度错误。

3- 第三个参数是一个函数,只要 observable 被标记为完成,就会调用该函数。

tap(observer, error, complete):Observable  

【讨论】:

以上是关于RxJS 6 /点击运算符何时发出值的主要内容,如果未能解决你的问题,请参考以下文章

如何在不需要 rxjs-compat 的情况下只导入 RxJS 6 中使用的运算符,如旧的 RxJS?

如何使用jasmine-marbles测试rxjs管道中的timeout()

RXJS 中的 startWith 运算符真的被弃用了吗?

如何基于另一个 Observable 重置 RXJS 扫描算子

如何使用 catchError() 并且仍然返回带有 rxJs 6.0 的类型化 Observable?

集中导入rxjs可租用运算符