我已经多次阅读ReactiveX文档,但仍然无法完全理解 Observer 订阅 Observable 时发生的情况。 / p>
让我们看一个简单的例子:
import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.complete();
});
const observer = {
next: (x) => console.log('got value ' + x),
error: (err) => console.error('something wrong occurred: ' + err),
complete: () => console.log('done')
};
observable.subscribe(observer);
我的问题:
传递给 Observable 的subscriber
对象从哪里来?
observable.subscribe
和subscribe
并非偶然new Observable(function subscribe(subscriber) {...})
具有相同的名称。 在库中,它们是不同的,但是出于实际目的,您可以 认为它们在概念上是平等的。
因此,显然,传递到 Observable 构造函数(subscriber
中的 subscribe 回调中的对象不是实际上是{ {1}}对象。至少如果您按照上面的引言讲解该库的实际工作原理,就可以了。
如果传入的不是observer
对象,那么observer
和subscriber.next(1)
的调用到底是什么?如何连接到subscribe.complete()
中的next
属性?
澄清性修改:
我知道如何利用 RxJS ,并且确实可以从概念上想象 Observer 被注入(如引文所述)。但是,我在这里希望了解它实际上的工作原理。
答案 0 :(得分:3)
Observable
创建过程的流程如下:
作者定义了Observable
(出于解释的目的,此处手动与new
一起定义):
const myObservable = new Observable(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.complete();
return function tearDownLogic() {
console.log('runs when Observable for whatever reason is done (complete, error, or unsubscribed)')
}
});
传递给以上subscribe
的{{1}}回调由Observable constructor在本地保存:
Observable
因此,我们保存了由我们或任何其他预制的constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {
if (subscribe) {
this._subscribe = subscribe;
}
}
定义的整个subscribe
函数,供以后执行。
可以以几种形式之一将 Observer 传递给Observable
回调。直接作为一到三个函数( next , error , complete ),或者作为具有相同三种方法中的一种或多种的对象。为了便于说明,我们将实现最后一个更详细的选项:
subscribe
现在,有趣的部分开始了。我们将const observer = {
next(v) {
console.log(v);
}
error(err) {
console.log(err);
}
complete() {
console.log('Observable has now completed and can no longer emit values to observer');
}
}
传递到observer
方法中:
Observable.subscribe(..)
subscribe method看起来像这样:
myObserver.subscribe(observer);
简要描述了 subscribe(observerOrNext?: PartialObserver<T> | ((value: T) => void),
error?: (error: any) => void,
complete?: () => void): Subscription {
const { operator } = this;
const sink = toSubscriber(observerOrNext, error, complete);
if (operator) {
sink.add(operator.call(sink, this.source));
} else {
sink.add(
this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
this._subscribe(sink) :
this._trySubscribe(sink)
);
}
if (config.useDeprecatedSynchronousErrorHandling) {
if (sink.syncErrorThrowable) {
sink.syncErrorThrowable = false;
if (sink.syncErrorThrown) {
throw sink.syncErrorValue;
}
}
}
return sink;
}
方法:
subscribe
observer
会将观察者转换为toSubscriber
对象,无论其以何种形式传递(Subscriber
实例都保存在Subscriber
变量中)sink
变量为operator
,除非您预订了运营商。因此,只需忽略undefined
周围的if
语句operator
扩展了Subscriber
对象(与原型链接),该对象的原型具有两个重要方法:Subscription
,unsubscribe()
add()
用于向add(..)
添加“ 拆解逻辑”(功能),当Observable
完成< / em>或取消订阅。它将采用传递给它的任何函数,将其包装在Observable
对象中,然后将该函数放入Subscription
的{{1}}变量中。此Subscription
保存在我们上面创建的_unsubscribe
上的变量Subscription
中。如前所述,我们这样做是为了使Subscriber
被取消订阅或完成时,所有由_subscriptions
编辑的拆解逻辑执行Subscriber
返回add()
实例。因此,您可以随时在其上调用Observable.subscribe()
以添加将在Subscriber
完成或退订 mySubscriber.add( // some tear down logic)
运行(在Observable
内部,作为参数)。 this._trySubscribe(sink)
是实际上运行add()
构造函数保存的_trySubscribe(..)
回调的函数。重要的是,它以subscribe
回调的形式传入Observable
(我们的新sink
实例)。换句话说,当执行Subscriber
中的Observable
时,我们实际上是在subscriber.next(1)
(Observable
)实例中执行next(1)
(sink
是在Subscriber
的原型上)。现在,这使我到最后。除其他事项外,next()
内和退订流程还有更多详细信息,但这些内容不在此问答中。
简而言之,要回答标题中的问题, Observer 实际上仅在转换为统一的Subscriber
对象之后才传递到toSubscribe
中。 / p>
希望这会在将来对其他人有所帮助。
答案 1 :(得分:2)
不,观察者没有被注入到可观察对象中。
AFAICT,这种困惑源自new Observable(...)
语法更多的是底层工厂,而不是有用的模式。
或多或少是of(value1, value2, ..., valueN)
,from(enumeration)
和fromEvent(...)
等更简单的实现所使用的机制。
这种方法是您应该重点关注的实际用例。
在幕后,所有这些方法都将某种同步或异步值或交互桥接到可观察流的奇妙世界。为此,它们以某种方式像适当的观察员那样行为:它们生成项目并将其放入流中。为此,他们使用了一个称为next
的函数。就像Observer
实现中的方法一样,实际上会以完全相同的方式调用bacause。
尤其是,您可以在此处查看subscription方法的实现:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts
如果您想了解订阅期间实际发生的情况,建议您实际看一下代码。 但是,IMO,只有在熟悉了各种Observable创建功能之后,您才应该尝试。
希望有帮助。