关于rxjs:使用subscription.next()是否是反模式?

Is it an antipattern to use subscription.next()?

我有一个订阅,我想用一段中间件代码来表示事件。所以我有一件事想要订阅一个可观察的东西,而另一件事却不是一个可观察的东西。

我考虑过为此使用主题-这就是它们的用途:

1
2
3
4
5
6
7
const repeater = new Rx.Subject();

function subscribe(observer) {
  return repeater.subscribe(observer);
}

// in some other function, call repeater.next(val)

但是后来我开始查看常规的subscription()调用返回了什么。我可以改为:

1
2
3
4
5
let sub = null;
function subscribe(observer) {
  return Rx.Observable.create((o) => sub = o);
}
// elsewhere sub.next(val)

但是也?

1
2
3
4
5
let unsub = null;
function subscribe(observer) {
  unsub = Rx.Observable.create(() => false).subscribe(observer)
}
// elsewhere unsub.next(val)

所有这些事情将向订户发出val信号。我在这里不明白的怪异之处是订阅返回有一个next()可用的-我认为next()仅存在于Observable上下文中的观察者上。

无论如何,我都需要处理取消订阅事务-当中间件被拆除时,我需要发出信号流完成并释放一些资源。令我惊讶的是,unsub的下一个功能正常。

这向我发出信号,就观察者,可观察对象和主题等而言,我还只是简单地了解了一些RxJS。通常,我了解如何将事件源和其他类似内容连接到可观察的流中。它实际上只是在从无聊的函数调用中构建可观察的流的上下文中-每当外部库调用该函数时,该流就会发出更新的可观察的信号。


订户扩展了订阅和观察者,添加了状态。它公开了一种更改状态的方法(即unsubscribe()),并且
它还公开了观察者的next() / error() / complete()方法,
但是这些方法现在既尊重状态又改变状态。

因此,如果我给您一个纯粹的观察者,您可以调用next() / error() / complete()
可以按任意顺序对其进行多次操作,即使
在您呼叫我的complete()之后呼叫您我的next()很糟糕。

另一方面,如果我给你一个观察者包裹在
订户,现在有状态,并且如果您尝试调用next()
在您呼叫complete()之后该订阅者,我不会看到它。
如果您呼叫unsubscribe(),我将被分离。

致电订阅时,如

1
subscriber = Rx.Observable.create(fn).subscribe(observer);

您要找回同一个观察者,而只有那个观察者,
包装在订户中。这就是为什么您看到next() / error() / complete()方法的原因。但是这些方法通常仅供内部使用,如果您使用它们来提供给观察者,它将无法完成您期望的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let observerA = {
    next: (x) => console.log('A: value: ' + x),
    error: (x) => console.log('A: error: ' + x),
    complete: () => console.log('A: completed')
}
let observerB = {
    next: (x) => console.log('B: value: ' + x),
    error: (x) => console.log('B: error: ' + x),
    complete: () => console.log('B: completed')
}

let observable = Rx.Observable.create(() => false);
let subscriberA = observable.subscribe(observerA);
let subscriberB = observable.map(x => 10*x).subscribe(observerB);
subscriberA.next(1); // only feeds observerA
// =>"A: value: 1"
subscriberB.next(2); // only feeds observerB
// =>"B: value: 2"  // What?

对于您的用例,您将很可能

  • 想要使用Subject,因为它为您提供了next() / error() / complete()接口,可让您养活运算符链的前端,
  • 想要使用Subject,因为它可以让您将相同的值提供给多个观察者,
  • 忘记您刚刚了解的关于订阅服务器的知识,因为您将不会使用next() / error() / complete()订阅服务器接口。而是将subscribe()返回的对象仅视为预订,并且仅在其上使用unsubscribe()方法。
  • 所以:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let subject = new Rx.Subject();
    let subscriptionA = subject.subscribe(observerA);
    let subscriptionB = subject.map(x=>10*x).subscribe(observerB);
    subject.next(3);
    // => A: value: 3
    // => B: value: 30
    subscriptionA.unsubscribe()
    subject.next(4);
    // => B: value: 40
    subscriptionB.unsubscribe()
    subject.next(5);
    // (no output)

    另请参见何时在rxjs中使用asObservable()?