是使用subscription.next()的反模式吗?

时间:2017-03-09 00:38:27

标签: rxjs rxjs5

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

我考虑过使用Subjects - 这就是他们的目的:

const repeater = new Rx.Subject();

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

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

但后来我开始查看常规subscribe()调用返回的内容。我可以这样做:

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

但也呢?

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

所有这些事情都会向订户发出信号。我在这里不理解的奇怪的事情是订阅返回有next()可用 - 我认为next()只存在于Observable上下文中的观察者。

我需要保留取消订阅doodad的处理,无论如何 - 当中间件被拆除时,我需要发信号流完成并释放一些资源。令我惊讶的是,unsub接下来有功能。

这告诉我,在Observers和Observables以及Subjects等方面,我还有一些RxJS,但我还没有理解。通常,我理解如何将事件源和其他类似的东西连接到可观察的流中。它实际上只是在一个无聊的函数调用中构建一个可观察的流的环境中 - 每当该函数被外部​​库调用时,该流就会发出一个更新的可观察信号。

1 个答案:

答案 0 :(得分:4)

订阅者扩展了Subscription和Observer,添加了状态。它暴露了一种改变状态的方法(即unsubscribe())和 它还暴露了观察者的next() / error() / complete()方法, 但这些方法现在既尊重国家又改变国家。

所以,如果我给你一个观察者,你可以致电next() / error() / complete() 在任何顺序上,尽可能多次,即使它会 在你打电话给我next()后,你可以打电话给我complete()

另一方面,如果我给你一个Observer包裹在一个 订阅者,现在有状态,如果您尝试拨打next() 在您致电complete()后,该订阅者,我不会看到它。 如果你打电话给unsubscribe(),我会被分开。

当您拨打订阅时,如

subscriber = Rx.Observable.create(fn).subscribe(observer);
你回到了同一个观察者,只有那个观察者, 包含在订阅者中。这就是您看到next() / error() / complete()方法的原因。但是这些方法通常供内部使用,如果你用它们来喂养观察者,它就不会按照你的期望做到:

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?

根据您的使用案例,您将

  1. 想要使用主题,因为它为您提供next() / error() / complete()接口,让您可以为运营商链的前端提供信息,
  2. 想要使用主题,因为它允许您向多个观察者提供相同的值,
  3. 忘记您刚刚了解的订阅者,因为您不会使用next() / error() / complete()订阅者界面。相反,请将subscribe()返回的对象仅视为订阅,并仅在其上使用unsubscribe()方法。
  4. 所以:

    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)
    

    另见When to use asObservable() in rxjs?