合并后我有两个合并的observable和一个扫描。第一个是简单范围,另一个是主题。每当Subject使用onNext
发出一个新值时,我会在扫描中连接该值并将新数组作为累加器返回。如果我处理了我的订阅,然后再次订阅,它会重放该范围内的值,但我丢失了主题中的值。在下面的代码中,我希望我的第二个订阅的最终值为[1, 2, 3, 4, 5]
最好的方法是什么?现在我有另一个主题,我存储了最终值并订阅了它,但它感觉错误。
这是一个简单的版本,演示了正在发生的事情:
var Rx = require('rx');
var source = Rx.Observable.range(1, 3);
var adder = new Rx.Subject();
var merged = source.merge(adder)
.scan([], function(accum, x) {
return accum.concat(x);
});
var subscription1 = merged.subscribe(function(x) {console.log(x)});
adder.onNext(4);
adder.onNext(5);
subscription1.dispose();
console.log('After Disposal');
var subscription2 = merged.subscribe(function(x) {console.log(x)});
输出:
[ 1 ]
[ 1, 2 ]
[ 1, 2, 3 ]
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
After Disposal
[ 1 ]
[ 1, 2 ]
[ 1, 2, 3 ]
答案 0 :(得分:7)
主题是一个热门的观察者,这就是为什么第二个订阅不会看到来自主题的事件。 Observable范围很冷,所以每个"执行实例"完全归每个订阅所有。另一方面,主题"执行实例"是单身且独立的,因此第二个订阅没有看到事件。
有几种方法可以解决这个问题。
但是,如果我对此问题的解释是正确的,那么您只需要merged
发出的最后一个事件,因此您可以使用替代(1)的变体,其中您只重放最后一个事件。这是将.shareReplay(1)
添加到merged
的问题,这将使其成为热门的重播Observable。
答案 1 :(得分:1)
根据您的说明,您似乎正在寻找BehaviorSubject
或ReplaySubject
(或其相应的运算符,publishValue()
和replay()
),而不是{{1} }。
每次重新访问页面时,您都可以使用以下方法来连接状态,(因为您提到它我将使用todo应用程序示例):
scan
这是一个工作代码示例我认为镜像你正在寻找的东西,注意在这种情况下我不需要扫描,因为列表被链条上的var todos = buttonClicked
.map(function(e) { return newTodoBox.text(); })
//This will preserve the state of the todo list across subscriptions
.replay();
var todoSubscription;
pageActivated.subscribe(function() {
todoSubscription = new Rx.CompositeDisposable(
//Add the items to the list
todos.subscribe(addItem),
//This enables the replay to actually start
//receiving values
todos.connect());
/*Do other activation work*/
});
pageDeactivated.subscribe(function() {
todoSubscription && todoSubscription.dispose();
/*Do other clean up work*/
});
完全重新水化。您会注意到,如果您添加了一些待办事项,那么请断开连接并再次连接,这些项目将重新出现。
replay()
var buttonClicked = Rx.Observable.fromEvent($('#add'), 'click');
var disconnect = Rx.Observable.fromEvent($('#disconnect'), 'click');
var connect = Rx.Observable.fromEvent($('#connect'), 'click');
var newTodoBox = $('#todos')[0];
var mylist = $('#mylist');
function addItem(e) {
mylist.append('<li>' + e + '</li>');
}
var todos = buttonClicked
.map(function(e) {
return newTodoBox.value;
})
.replay();
var todoSubscription;
disconnect.subscribe(function() {
mylist.empty();
todoSubscription && todoSubscription.dispose();
});
connect.startWith(true).subscribe(function() {
todoSubscription = new Rx.CompositeDisposable(
todos.subscribe(addItem),
todos.connect());
});