theatre/packages/dataverse/src/derivations/DerivationEmitter.ts

65 lines
1.9 KiB
TypeScript
Raw Normal View History

2021-06-18 13:05:06 +02:00
import type Ticker from '../Ticker'
import Emitter from '../utils/Emitter'
import type {default as Tappable} from '../utils/Tappable'
import type {IDerivation} from './IDerivation'
2022-01-19 13:06:13 +01:00
/**
* An event emitter that emits events on changes to a derivation.
*/
2021-06-18 13:05:06 +02:00
export default class DerivationEmitter<V> {
private _derivation: IDerivation<V>
private _ticker: Ticker
private _emitter: Emitter<V>
private _lastValue: undefined | V
private _lastValueRecorded: boolean
private _hadTappers: boolean
2022-01-19 13:06:13 +01:00
/**
2022-02-23 22:53:39 +01:00
* @param derivation - The derivation to emit events for.
* @param ticker - The ticker to use to batch events.
2022-01-19 13:06:13 +01:00
*/
2021-06-18 13:05:06 +02:00
constructor(derivation: IDerivation<V>, ticker: Ticker) {
this._derivation = derivation
this._ticker = ticker
this._emitter = new Emitter()
this._emitter.onNumberOfTappersChange(() => {
this._reactToNumberOfTappersChange()
})
this._hadTappers = false
this._lastValueRecorded = false
this._lastValue = undefined
return this
}
private _possiblyMarkAsStale = () => {
this._ticker.onThisOrNextTick(this._refresh)
}
private _reactToNumberOfTappersChange() {
const hasTappers = this._emitter.hasTappers()
if (hasTappers !== this._hadTappers) {
this._hadTappers = hasTappers
if (hasTappers) {
this._derivation.addDependent(this._possiblyMarkAsStale)
} else {
this._derivation.removeDependent(this._possiblyMarkAsStale)
}
}
}
2022-01-19 13:06:13 +01:00
/**
* The tappable associated with the emitter. You can use it to tap (subscribe to) the underlying derivation.
*/
2021-06-18 13:05:06 +02:00
tappable(): Tappable<V> {
return this._emitter.tappable
}
private _refresh = () => {
const newValue = this._derivation.getValue()
if (newValue === this._lastValue && this._lastValueRecorded === true) return
this._lastValue = newValue
this._lastValueRecorded = true
this._emitter.emit(newValue)
}
}