我创建了自己的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?
答案 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。
这是一个使用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)
将您的代码更改为这样的内容,它会起作用。这里的重点是每个订阅都是通过其对应的订阅者更新的,如果你有多个订阅,你必须通知多个订阅者。就您而言,您刚刚通知了最后一个。