RxJS对Observable的多个订阅?

时间:2016-04-23 18:49:22

标签: javascript rxjs

我创建了自己的observable并为其订阅了两个函数。我希望对序列中的每个元素执行两个函数,但只有最后一个元素。

let observer = null
const notificationArrayStream = Rx.Observable.create(function (obs) {
  observer = obs;
  return () => {}
})

function trigger(something) {
  observer.next(something)
}

notificationArrayStream.subscribe((x) => console.log('a: ' + x))
notificationArrayStream.subscribe((x) => console.log('b: ' + x))

trigger('TEST')

预期输出

a: TEST
b: TEST

实际输出

b: TEST

这是JSBin:http://jsbin.com/cahoyey/edit?js,console

为什么?如何让多个函数订阅一个Observable?

6 个答案:

答案 0 :(得分:46)

主题

在您的情况下,您只需使用Subject即可。当subject使用它作为一组订阅者和来源的代理时,{strong}允许您与多个观察者共享一次执行

从本质上讲,这是使用主题的示例:

const subject = new Subject();

function trigger(something) {
    subject.next(something);
}

subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));

trigger('TEST');

结果:

a: TEST
b: TEST

陷阱:观察员来得太晚

请注意,您订阅的时间和广播数据的时间是相关的。如果您在订阅前发送广播,则不会收到此广播通知:

function trigger(something) {
    subject.next(something);
}

trigger('TEST');

subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));

结果:(空)

ReplaySubject& BehaviorSubject

如果您想确保即使将来的订阅者都会收到通知,您也可以使用ReplaySubjectBehaviorSubject

这是一个使用ReplaySubject的示例(缓存大小为5,意味着将记住过去最多5个值,而 BehaviorSubject 只能记住最后一个值):

const subject = new ReplaySubject(5); // buffer size is 5

function trigger(something) {
    subject.next(something);
}

trigger('TEST');

subject.subscribe((x) => console.log('a: ' + x));
subject.subscribe((x) => console.log('b: ' + x));

结果:

a: TEST
b: TEST

答案 1 :(得分:18)

要让多个函数订阅一个Observable,只需将它们订阅到那个observable,就这么简单。实际上,这就是你所做的。

但是您的代码无效,因为执行notificationArrayStream.subscribe((x) => console.log('b: ' + x))后,observer(x) => console.log('b: ' + x)),因此observer.next会为您提供b: TEST

所以基本上你的可观察创作是错误的。在create中,您传递了一个观察者作为参数,因此您可以传递它的值。你需要通过自己的逻辑以某种方式生成这些值,但正如你可以看到你的逻辑是错误的。如果你想将值推送给观察者,我建议你使用一个主题。

类似的东西:

const notificationArrayStream = Rx.Observable.create(function (obs) {
  mySubject.subscribe(obs);
  return () => {}
})

function trigger(something) {
  mySubject.next(something)
}

答案 2 :(得分:4)

每次订阅时,您都会覆盖var observer

触发器函数只引用这一个var,因此只有一个日志就不足为奇了。

如果我们将var设为数组,则按预期工作: JS Bin

let obs = [];

let foo = Rx.Observable.create(function (observer) {
  obs.push(observer);
});

function trigger(sth){
//   console.log('trigger fn');
  obs.forEach(ob => ob.next(sth));
}

foo.subscribe(function (x) {
  console.log(`a:${x}`);
});
foo.subscribe(function (y) {
  console.log(`b:${y}`);
});

trigger(1);
trigger(2);
trigger(3);
trigger(4);

更清洁的解决方案是使用Subject,如上所述。

答案 3 :(得分:1)

可观察对象不是多播;除非您使用任何类型的Subject。当然,您可以创建主题,将Observable的输出通过管道传递到其他答案提议中。

但是,如果您已经拥有Observalbe,则使用share()可以更方便地将Observable变成Subject或{{ 1}}与shareReplay(n)等效:

ReplaySubject(n)

就是这样。

答案 4 :(得分:0)

除了使用Subject之外,还可以使用publishReplay() + refCount() combo允许observable多播到多个订阅者:

const notificationArrayStream = Rx.Observable.create(function (obs) {
  observer = obs;
  return () => {}
}).pipe(publishReplay(), refCount())

答案 5 :(得分:0)

const subs = []

const ob = new Observable((s) => {
  console.log('called')
  subs.push(s)
})

const trigger = (v) => {
  subs.forEach((sub) => {
    sub.next(v)
  })
}

ob.subscribe((v) => {
  console.log('ob1', v)
})

ob.subscribe((v) => {
  console.log('ob2', v)
})

trigger(1)

将您的代码更改为这样的内容,它会起作用。这里的重点是每个订阅都是通过其对应的订阅者更新的,如果你有多个订阅,你必须通知多个订阅者。就您而言,您刚刚通知了最后一个。