我一直在学习RxJs,我在尝试确定使用scan和combinelatest时看到的输出背后的逻辑时遇到了问题
我有这个示例应用程序
var subject = new Rx.Subject();
var stream = subject.map(function(x) {
return function(v) {
return v + " stream";
};
});
var state = Rx.Observable.merge(stream)
.startWith("StartWith")
.scan(function(x, f) {
console.log("scan");
return f(x);
});
var view1 = state.map(function(x) {
return "view1 " + x;
});
var view2 = state.map(function(x) {
return " view2 " + x;
});
Rx.Observable.combineLatest(view1, view2, function(x, y) {
return [x, y].join(",");
}).subscribe(function(x) {
console.log(x);
});
subject.onNext("Once");
subject.onNext("Twice");

当您查看应用程序的控制台日志时,它会输出以下内容
LOG: view1 StartWith, view2 StartWith,
LOG: scan
LOG: view1 StartWith stream, view2 StartWith,
LOG: scan
LOG: view1 StartWith stream, view2 StartWith stream,
LOG: scan
LOG: view1 StartWith stream stream, view2 StartWith stream,
LOG: scan
LOG: view1 StartWith stream stream, view2 StartWith stream stream,
我不明白为什么经常调用扫描。我只是为主题调用了两次,但似乎是4次调用扫描功能。如果我添加更多视图,它将再添加2个扫描调用,依此类推。
任何人都可以解释为什么会这样吗?
答案 0 :(得分:7)
因为你订阅了两次。 CombineLatest
将隐式订阅您传递的两个流。当您第一次使用Rx时,这是非常常见的错误,除非运营商声称为每个订阅共享基础可观察量,否则每个订阅都会创建一个新可观察流。
也就是说,上面的代码在功能上与以下代码相当(但实际上并没有这样做):
var subject = new Rx.Subject();
var source1 = subject
.map(function(x) {
return function(v) {
return v + " stream";
};
})
.startWith("StartWith")
.scan(function(x, f) {
console.log("scan");
return f(x);
}).map(function(x) {
return "view1 " + x;
});
var source2 = subject
.map(function(x) {
return function(v) {
return v + " stream";
};
})
.startWith("StartWith")
.scan(function(x, f) {
console.log("scan");
return f(x);
})
.map(function(x) {
return " view2 " + x;
})
var x, y;
source1.subscribe(function(_x) {
x = _x;
if (typeof y !== 'undefined') {
console.log([x, y].join(","));
});
source2.subscribe(function(_y) {
y = _y;
if (typeof x !== 'undefined') {
console.log([x, y].join(","));
});
subject.onNext("Once");
subject.onNext("Twice");
如果您希望仅扫描一次扫描,则应在scan()
之后使用share()
,以便Observable
之间的scan
将在订阅者之间共享。
所以state
应该是:
var state = Rx.Observable.merge(stream)
.startWith("StartWith")
.scan(function(x, f) {
console.log("scan");
return f(x);
})
.share();