RxJS 5.5.2
我正在使用以下代码将一组数字拆分为一个对象,其中包含2个属性'small',用于小于4的数字和'big'其余部分。
const o = from([1, 2, 3, 4, 5, 6]).pipe(
scan<number, {}>((a, b) => {
if (b < 4) {
a['small'].push(b);
} else {
a['big'].push(b);
}
return a;
}, {
'small': [],
'big': []
})
);
console.log('subscription 1');
o.subscribe(x => console.log(JSON.stringify(x)));
console.log('subscription 2');
o.subscribe(x => console.log(JSON.stringify(x)));
订阅1台控制台打印后:
{"small":[1,2,3],"big":[4,5,6]} // this is ok
订阅后2台控制台打印:
{"small":[1,2,3,1,2,3],"big":[4,5,6,4,5,6]} // this is not ok
每次有人订阅时,有没有办法以新的种子对象开始?
答案 0 :(得分:2)
扫描累加器({ small: [], big: [] }
)使用.push
进行变异,这是一种反模式,很容易导致意外行为。
防止更改先前发出的值的一个选项可能是:
scan<number, {}>((a, b) => {
if (b < 4) {
return Object.assign({}, a, {small: a.small.concat([b])});
} else {
return Object.assign({}, a, {big: a.big.concat([b])});
}
}, {
'small': [],
'big': []
})
不确定您要完成的是什么,但是查看partition
运算符可能是值得的,它会产生两个独立的值流,如const [small, big] = someStream.partition(x => x < 4);
。
答案 1 :(得分:2)
另一个选择是将管道包装在defer
块中,该块将在订阅时重建源流。
defer(() =>
from([1, 2, 3, 4, 5, 6]).pipe(
scan<number, {}>((a, b) => {
if (b < 4) {
a['small'].push(b);
} else {
a['big'].push(b);
}
return a;
}, {
'small': [],
'big': []
})
)
);
每个订阅都会在defer块中调用该方法并订阅结果。虽然正如@arturgrzesiak所提到的,变异数组在函数式编程和扩展函数式反应式编程中被视为反模式。