如何在subscribe方法中退订RXJS订阅?

时间:2020-10-14 09:52:52

标签: rxjs rxjs-observables

我有一些javascript:

this.mySubscription = someObservable.subscribe((obs: any) => {
   this.mySubscription.unsubscribe();
   this.mySubscription = undefined;
}

执行时,控制台记录错误ERROR TypeError: Cannot read property 'unsubscribe' of undefined。 我想知道为什么我不能取消订阅lambda函数。有正确的方法吗?我已经阅读了一些有关使用虚拟对象并完成它们或使用takeUntil / takeWhile和其他管道运算符workArounds的知识。

在订阅的订阅功能内取消订阅的正确方法/解决方法是什么?

我目前正在使用虚拟订阅,例如:

mySubscription: BehaviorSubject<any> = new BehaviorSubject<any>(undefined);


// when I do the subscription:
dummySubscription: BehaviorSubject<any> = new BehaviourSubject<any>(this.mySubscription.getValue());
this.mySubscription = someObservable.subscribe((obs: any) => {
    // any work...
    dummySubscription.next(obs);
    dummySubscription.complete();
    dummySubscription = undefined;
}, error => {
    dummySubscription.error(error);
});

dummySubscription.subscribe((obs: any) => {
    // here the actual work to do when mySubscription  emits a value, before it should have been unsubscribed upon
}, err => {
    // if errors need be
});

2 个答案:

答案 0 :(得分:2)

您不应尝试在subscribe函数中退订。
您可以取消订阅taketakeWhiletakeUntil之类的运算符。

服用

take(n)发出someObservable次之后,使用n退订。

someObservable.pipe(
  take(1)
).subscribe(value => console.log(value));

takeWhile

当发射的值不符合条件时,使用takeWhile取消订阅。

someObservable.pipe(
  takeWhile(value => valueIsSave(value))
).subscribe(value => console.log(value));

valueIsSave(value): boolean {
  // return true if the subscription should continue
  // return false if you want to unsubscribe on that value
}

takeUntil

当观察到的takeUntil(obs$)发出时,请使用obs$退订。

const terminate = new Subject();

someObservable.pipe(
  takeUntil(terminate)
).subscribe(value => console.log(value));

unsub() { 
  terminate.next() // trigger unsubscribe
}

答案 1 :(得分:0)

如果使流异步,则您正在执行的操作应该可以进行。例如,这将不起作用:

const sub = from([1,2,3,4,5,6,7,8,9,10]).subscribe(val => {
  console.log(val);
  if(val > 5) sub.unsubscribe();
});

但这将起作用:

const sub2 = from([1,2,3,4,5,6,7,8,9,10]).pipe(
  delay(0)
).subscribe(val => {
  console.log(val);
  if(val > 5) sub2.unsubscribe();
});

由于JS事件循环是相当可预测的(代码块始终运行到完成),如果流的任何部分都是异步的,则可以确定将在调用lambda回调之前定义订阅。 / p>

您应该这样做吗?

可能不是。如果您的代码依赖于您的语言/编译器/解释器/等的内部(否则为隐藏的)机密,则您已经创建了易碎的代码和/或难以维护的代码。下一位正在查看我的代码的开发人员将对为什么会有delay(0)感到困惑-看来它不应该做任何事情。

请注意,在subscribe()中,您的lambda可以访问其闭包以及当前的流变量。 takeWhile()运算符可以访问相同的闭包和相同的流变量。

from([1,2,3,4,5,6,7,8,9,10]).pipe(
  takeWhile(val => {
    // add custom logic
    return val <= 5;
  })
).subscribe(val => {
  console.log(val);
});

takeWhile()可以处理sub = subscribe(... sub.unsubscibe() ... )的任何内容,并具有不需要管理订阅对象并且易于读取/维护的额外好处。