@johngw/stream
Version:
Reactive programming tools using the WHATWG Streams API.
90 lines (76 loc) • 2.17 kB
text/typescript
import { DebounceBehavior } from '#transformers/debounce/Behavior'
import { DebounceState } from '#transformers/debounce/State'
/**
* The transformer implementation for {@link debounce:function}.
*
* @group Transformers
* @see {@link debounce:function}
*/
export class DebounceTransformer<T> implements Transformer<T, T> {
#behaviors: DebounceBehavior<T>[]
#state: DebounceState
constructor(ms: number, behaviors: DebounceBehavior<T>[]) {
this.#behaviors = behaviors
this.#state = this.#reduceState('init', { ms, queued: false })
}
transform(chunk: T, controller: TransformStreamDefaultController<T>) {
this.#preTimer(chunk, controller)
this.#timer(chunk, controller)
}
flush() {
clearTimeout(this.#state.timer)
}
#preTimer(chunk: T, controller: TransformStreamDefaultController<T>) {
clearTimeout(this.#state.timer)
this.#state = this.#reduceState(
'preTimer',
{
...this.#state,
queued: false,
},
chunk,
controller
)
}
#timer(chunk: T, controller: TransformStreamDefaultController<T>) {
this.#state = {
...this.#state,
timer: setTimeout(
() => this.#postTimer(chunk, controller),
this.#state.ms
),
}
}
#postTimer(chunk: T, controller: TransformStreamDefaultController<T>) {
clearTimeout(this.#state.timer)
this.#state = this.#reduceState(
'postTimer',
{
...this.#state,
timer: undefined,
},
chunk,
controller
)
}
#reduceState(stage: 'init', state: DebounceState): DebounceState
#reduceState(
stage: 'preTimer' | 'postTimer',
state: DebounceState,
chunk: T,
controller: TransformStreamDefaultController<T>
): DebounceState
#reduceState(
stage: keyof DebounceBehavior<T>,
state: DebounceState,
chunk?: T,
controller?: TransformStreamDefaultController<T>
): DebounceState {
return this.#behaviors.reduce(
(state, behavior) =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
behavior[stage]?.(state, chunk!, controller!) || state,
state
)
}
}