【问题标题】:cancelling a observable with takeUntil not working用 takeUntil 取消 observable 不起作用
【发布时间】:2018-05-11 09:48:46
【问题描述】:

我有一个自动完成 HTTP 调用和一个执行搜索 HTTP 调用...我需要在触发执行操作时中止自动完成调用。我现在正在做的是使用这样的主题:

private onExecute$ = new Subject();

在我的自动完成方法中:

executeAutoComplete(e) {
  this.myService.searchAutoComplete(e.criteria)
  .pipe(
   takeUntil(this.onDestroy$),
   takeUntil(this.onExecute$),
   map( 
  // continue with more code

然后在我的执行方法中发出信号:

executeSearch(e) {
console.log('triggering onExecute signal');
this.onExecute$.next();
  // other code
}

所以在我的控制台中,我看到“触发 onExecute 信号”,但自动完成结果在完整搜索开始执行后返回,我认为一旦我发出信号,takeUntil 将中止链?它不起作用。

所以基本上我试图阻止的行为是,当用户触发搜索时,自动完成结果不应该返回并打开下拉列表,因为它不再相关。

我在这里错过了什么?

编辑 -

由于总是在自动完成之前调用执行的去抖动时间,顺序实际上是问题,顺序可能是不可预测的。没有意识到如果 Observable 链尚未激活,onExecute.next() 将丢失。

我确实也设置了一个 searchLoading 变量,我该如何使用它?

我试过了:

takeUntil(Observable.of(this.searchLoading))

这是行不通的,因为它总是正确的!如何将 takeUntil 与动态评估的布尔值一起使用?

编辑 2 -

使用 takeWhile 得到它:

takeWhile(() => !this.searchLoading))

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    会不会是 executeSearchexecuteAutoComplete 之前被调用?如果onExecute$ 在构造可观察链之前已经发出了一个不会停止执行搜索的值。

    顺便说一句:在我看来,运行搜索时在订阅上调用unsubscribe 会更简单。

    【讨论】:

    • 您可以在任何地方使用变量 (takeUntil(()=>this.alive) 并将变量 this.alive 切换为 true。我不确定 this.onDestroy$ 是否随时变为 false
    • 将检查顺序...当用户输入文本时,子组件向父组件发出change事件,当用户按下回车键或点击搜索时发出执行事件图标,从技术上讲,更改事件(自动完成)应该在输入键(执行)之前发出,因为这是用户操作的顺序,但它可能不一定是这个顺序......更改有 400 毫秒的去抖动,因此可能导致问题!
    • 我在原来的问题中添加了评论,谢谢!
    【解决方案2】:

    坏消息是,它有效。

    我一直在尝试使用您的代码的这种近似值来查找缺陷,但不幸的是找不到。
    我把它贴在这里以防它对某人有用。

    console.clear()
    
    const takeUntil = Rx.operators.takeUntil;
    
    const onDestroy$ = new Rx.Subject();
    const onExecute$ = new Rx.Subject();
    
    const source$ = Rx.Observable.timer(0,1000)
    const executeAt$ = Rx.Observable.timer(3000)
    
    executeAt$
      .subscribe(x => {
         console.log('execute');
         onExecute$.next(); 
       })
    
    source$
      .pipe(
        takeUntil(onDestroy$), 
        takeUntil(onExecute$)
      )
      .subscribe(console.log)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>

    关于unsubscribe()takeUntil() 的主题,'Don't Unsubscribe' Ben Lesh 说

    保留太多订阅对象表明您在强制管理订阅,而不是利用 Rx 的强大功能。

    使用 takeUntil 编写您的订阅管理


    脚注 - 服务实例

    鉴于 Rx 代码看起来不错,另一个可能的原因是 Angular 服务的多个实例。

    如果 private onExecute$ = new Subject(); 被包装在一个服务中,并且您在两个提供数组中拥有该服务(例如在一个模块 + 一个组件中,或者在两个组件中),那么您调用 .next() 的实例可能不同于takeUntil() 中使用的实例。

    这是一个长镜头,上面的代码表明情况并非如此,但似乎很常见。

    【讨论】:

    • 感谢代码 sn-p,因为这个概念有效(就像我认为的那样)让我更仔细地查看代码,也许我在某个地方遗漏了一些东西......
    【解决方案3】:

    它很旧,但我有同样的场景。

    如果要使用 takeUntil,正确的 Subject 是 ReplaySubject。

    • 因为如果 Subject 在调用 takeUntil 之前发出任何内容,当 takeUntil 订阅 Subject 时它不会重新发送(与实现一样),并且 takeUntil 不会取消订阅源。
    • 另一方面,ReplaySubject 会在订阅时重新发送,因此 takeUntil 将取消其内部取消订阅调用。

    【讨论】:

      猜你喜欢
      • 2018-12-25
      • 1970-01-01
      • 2018-11-05
      • 1970-01-01
      • 2018-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多