使用独立触发器的解决方案让我困扰的一件事是fullBufferTrigger 不知道timeoutTrigger 何时发出它的一个缓冲值,所以给定正确的事件序列,fullBuffer 将在超时后提前触发。
理想情况下,希望fullBufferTrigger 在timeoutTrigger 触发时重置,但事实证明这样做很棘手。
使用bufferTime()
在 RxJS v4 中有一个运算符 bufferWithTimeOrCount(timeSpan, count, [scheduler]),在 RxJS v5 中它被卷成一个附加签名 bufferTime()(从清晰的角度来看可能是一个错误)。
bufferTime<T>(
bufferTimeSpan: number,
bufferCreationInterval: number,
maxBufferSize: number,
scheduler?: IScheduler
): OperatorFunction<T, T[]>;
剩下的唯一问题是如何合并window.beforeunload 触发器。查看bufferTime 的源代码,它应该在接收到onComplete 时刷新它的缓冲区。
因此,我们可以通过向缓冲的事件流发送 onComplete 来处理window.beforeunload。
bufferTime 的规范没有对 onComplete 进行明确的测试,但我想我已经设法将它们放在一起。
注意事项:
- 将超时设置为较大,以便将其从图片中取出以进行测试。
- 源事件流不受影响,说明添加了 event8 但从不发出,因为窗口在它发生之前就被破坏了。
- 要查看没有 beforeunloadTrigger 的输出流,请注释掉发出onComplete 的行。 Event7 在缓冲区中,但不会发出。
测试:
const bufferPeriodMs = 7000 // Set high for this test
const bufferSize = 2
const event$ = new Rx.Subject()
/*
Create bufferedEvent$
*/
const bufferedEvent$ = event$
.bufferTime(bufferPeriodMs, null, bufferSize)
.filter(events => events.length > 0)
const subscription = bufferedEvent$.subscribe(console.log)
/*
Simulate window destroy
*/
const destroy = setTimeout( () => {
subscription.unsubscribe()
}, 4500)
/*
Simulate Observable.fromEvent(window, 'beforeunload')
*/
const beforeunloadTrigger = new Rx.Subject()
// Comment out the following line, observe that event7 does not emit
beforeunloadTrigger.subscribe(x=> event$.complete())
setTimeout( () => {
beforeunloadTrigger.next('unload')
}, 4400)
/*
Test sequence
Event stream: '(123)---(45)---6---7-----8--|'
Destroy window: '-----------------------x'
window.beforeunload: '---------------------y'
Buffered output: '(12)---(34)---(56)---7'
*/
event$.next('event1')
event$.next('event2')
event$.next('event3')
setTimeout( () => { event$.next('event4'); event$.next('event5') }, 1000)
setTimeout( () => { event$.next('event6') }, 3000)
setTimeout( () => { event$.next('event7') }, 4000)
setTimeout( () => { event$.next('event8') }, 5000)
工作示例:CodePen