观察者是否是RxJS中可观察者的“听者”?

时间:2019-09-09 16:51:49

标签: javascript rxjs observable

我正在学习RxJS,对于“侦听器”的位置(在“观察者”或“观察者”中),如何订阅/取消订阅以及观察者“不再感兴趣”会发生什么,我感到很困惑。可观察到的,例如当您使用taketakeUntil时。

对于第一部分-订阅了什么,听众是什么-我对这些语句之间的看似矛盾感到困惑。从http://reactivex.io/rxjs/manual/overview.html中,我们看到观察者不是观察者的“听者”

  

与事件处理程序API(例如,   addEventListener / removeEventListener。使用observable.subscribe,   给定的Observer未在Observable中注册为侦听器。的   Observable甚至不维护附加的观察者的列表。

但是在http://reactivex.io/learnrx/中,(练习30)(强调我的意思)说

  

基于事件的可观察对象将永远无法独立完成。的   take()函数创建一个新的序列,该序列在离散后完成   物品数量到达。这很重要,因为与事件不同,   当可观察序列完成时,将取消订阅其所有   听众。这意味着如果我们使用take()完成事件   顺序,我们不需要退订!

这似乎与我矛盾。例如,使用fromEvent设置Observable时,事件侦听器在哪里?例如,当您在基于DOM事件的Observable上使用take(1)时,在将第一个事件发送给观察者之后会发生什么? Observable会继续发出事件的Observable中的 unsubscribe ,仅仅是Observer不再监听它们了吗?还是Observable取消订阅Observer,即eventListener在Observable中,而不是Observer中?

感谢任何线索-显然我没有看到树木茂盛的树木,但是我正在研究的教程虽然擅长从概念上解释它,但我对实际发生的事情感到困惑

1 个答案:

答案 0 :(得分:3)

第一部分对单词的使用非常特别,以强调预订可观察对象是调用一个函数(或更可能是一系列函数)来运行它们包含的所有代码的问题。第二部分不太讲究其措辞,但实际上并不是在谈论同一件事。如果愿意的话,第二部分的措辞最好是“当一个可观察对象完成时,它将对观察者调用拆卸逻辑。

让我尝试描述当我说订阅一个可观察对象是调用函数链的问题时的意思。考虑以下超级简单的示例:

对于一个超简单的示例,假设我创建了这个可观察的:

const justOne = Rx.Observable.create(function realSubscribe(observer) {
  observer.next(1);
  observer.complete();
});

justOne.subscribe(val => console.log(val));

如果我随后调用justOne.subscribe(val => console.log(val)),则将立即调用我名为realSubscribe的函数。然后,它执行observer.next(1),导致注销val,然后执行observer.complete()。就是这样。

在此过程中,可观察的位置没有创建或增加订户列表的位置;它只是顺序地运行了代码,然后完成了。


现在来看一个更现实的示例,让我们考虑fromEvent。如果我要实现它,它可能看起来像这样(real implementation更加复杂,但这可以理解它的要旨):

function fromEvent(element, eventName) {
  return Rx.Observable.create(function subscribeToEvent(observer) {
    element.addEventListener(eventName, observer.next);
    return function cleanup() {
      element.removeEventListener(eventName, observer.next);
    }
  });
}

const observable = fromEvent(document, 'click');
const subscription = observable.subscribe(event => console.log(event));

现在,当我调用observable.subscribe时,它将运行subscribeToEvent,并以此在文档上调用addEventListener。 document.addEventListener 确实会导致文档保留事件侦听器列表,但这是因为实现了addEventListener的方式,而不是所有可观察对象所共有的方式。可观察对象本身不会跟踪任何侦听器。它只是调用被告知要调用的内容,然后返回清除函数。


接下来,让我们看看拍摄。和之前的real implementation一样,它的工作也很复杂:

// In the real `take`, you don't need to pass in another observable since that's
// available automatically from the context you called it in. But my sample code
// has to get it somehow.
function take(count, otherObservable) {
  return new Observable(function subscribeToTake(observer) {
    let soFar = 0;
    otherObservable.subscribe((value) => {
      observer.next(value);
      soFar++;
      if (soFar >= count) {
        observer.complete();
      }
    });
  });
}

const clickObservable = fromEvent(document, 'click');
take(1, clickObservable).subscribe(event => console.log(event))

正如评论中提到的那样,我使用的语法与rxjs中使用的语法不太匹配,但这是因为要模仿它需要更完整的实现。无论如何,吸引您注意的主要事情是我们开始产生一系列功能:

当我打电话给.subscribe时,那会叫subscribeToTake。这将设置一个计数器,然后调用otherObservable.subscribe,即subscribeToEvent。然后,subscribeToEvent调用document.addEventListener。

Take的工作是坐在这个功能链的中间。它跟踪到目前为止已发出了多少个值。如果计数足够低,它只会转发值。但是一旦达到计数,它将调用完成,从而结束可观察的。调用完成将导致可观察对象运行其具有的任何拆解逻辑或链中具有的任何逻辑。 take没有拆卸逻辑,但是fromEvent将运行一些拆卸逻辑以删除事件侦听器。