观察者退订后,可观察者是否继续发出值?

时间:2019-12-15 15:11:37

标签: angular rxjs observable

让我们考虑以下示例代码:

gude() {
  const digestor$ = new Observable(subscriber => {
    for (let i = 0; i < 4711; i++) {
      setTimeout(() => {
        const hash = createHashWithNLeadingZeroes(i);
        subscriber.next(hash);
      }, i);
    }
  });

  const subscription = digestor$.subscribe(
    _ => {
      if (subscription) {
        subscription.unsubscribe();
      }
    }
  );
}

在函数 gude()中,创建了一个新的observable,该对象发出的哈希值将前 n 个前导值设置为零。观察者订阅了该可观察的内容,并立即取消了订阅。假设函数 createHashWithNLeadingZeroes()花费大量时间来生成响应。

恕我直言,以下情况正在发生:

(1)创建一个新的Observable,并将描述Observable行为的函数内部存储在属性 _subscribe https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts:37-41)中。

(2)调用 subscribe()时,首先将Observer包裹在 Subscriber 对象中,然后再应用 Subscriber _subscribe 函数,该函数保留了Observable的逻辑。 _subscribe()会快速返回,因为仅设置了4711超时,并返回了Subscription对象(https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts:206-250)。

订阅服务器基本上拦截对 next() error() complete()的调用,并且仅在以下情况下转发给实际的观察者:内部未设置属性 isStopped https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts:90-128)。

(3)一旦设置了变量 subscription ,就会调用 unsubscribe()。除其他外,这将导致将 isStopped 设置为true,以便订阅服务器不再将哈希转发给观察者(https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts:130-136)。

根据该逻辑,可观察对象仍将继续执行其工作,直到无目的地计算了所有4711个哈希,因为观察者的方法变为无操作。最终,这种行为可能会影响应用程序的性能,具体取决于订阅量和Observable的工作量。我发现很难相信所描述的是正确的。我在这里想念哪一部分?

2 个答案:

答案 0 :(得分:1)

  

我在哪部分想念?

我认为您缺少的部分是遵守合同的观察员的责任:如果要求其停止排放,则应停止排放。因此,您的观察对象应执行以下操作:

const digestor$ = new Observable(subscriber => {
  let keepGoing = true;
  for (let i = 0; i < 4711 && keepGoing; i++) {
    setTimeout(() => {
      if (keepGoing) {
        const hash = createHashWithNLeadingZeroes(i);
        subscriber.next(hash);
      }
    }, i);

    return () => keepGoing = false; // this function is called when the subscriber unsubscribes
  }
});

通常最好的方法是依靠现有的工厂功能和操作员来实现所需的行为。例如,您可以通过使用range()timer()map()来实现与上述可观察到的等效。

答案 1 :(得分:1)

您正在创建"hot" Observable,因此即使没有订阅者,它也会发出。

使用new Observable()创建Observable时,您可以选择返回所谓的拆解(或处理)函数,该函数应在需要时清理所有资源。

因此,您需要停止计时器。

new Observable(subscriber => {
  ...
  const handler = setTimeout(() => {...});

  return () => clearTimeout(handler);
});

或者,如果您有多个计时器,您将在所有计时器上调用clearTimeout