你可以使用 window 和 share 源 Observable。 bufferCount(2, 1)还有一个小技巧:
const str = 'a-a-a-a-a-b-b-b-b-c-c-c-c-d-d-d-e';
const source = Observable.from(str.split('-'), Rx.Scheduler.async).share();
source
.bufferCount(2, 1) // delay emission by one item
.map(arr => arr[0])
.window(source
.bufferCount(2, 1) // keep the previous and current item
.filter(([oldValue, newValue]) => oldValue !== newValue)
)
.concatMap(obs => obs.toArray())
.subscribe(console.log);
这个打印(因为toArray()):
[ 'a', 'a', 'a', 'a', 'a' ]
[ 'b', 'b', 'b', 'b' ]
[ 'c', 'c', 'c', 'c' ]
[ 'd', 'd', 'd' ]
[ 'e' ]
这个解决方案的问题是订阅source 的顺序。我们需要window 通知程序在第一个bufferCount 之前订阅。否则,一个项目首先被进一步推送,然后检查它是否与 .filter(([oldValue, newValue]) ...) 上一个项目不同。
这意味着需要在window 之前将发射延迟一个(即第一个.bufferCount(2, 1).map(arr => arr[0])。
或者用publish()自己控制订阅顺序可能更容易:
const str = 'a-a-a-a-a-b-b-b-b-c-c-c-c-d-d-d-e';
const source = Observable.from(str.split('-'), Rx.Scheduler.async).share();
const connectable = source.publish();
connectable
.window(source
.bufferCount(2, 1) // keep the previous and current item
.filter(([oldValue, newValue]) => oldValue !== newValue)
)
.concatMap(obs => obs.toArray())
.subscribe(console.log);
connectable.connect();
输出是一样的。