Compare commits

...

1 Commits

Author SHA1 Message Date
Anselm
6f13a05c36 Sketch for throttling & value equality 2024-06-26 13:45:43 +01:00
2 changed files with 74 additions and 6 deletions

View File

@@ -127,20 +127,20 @@ export function createJazzReactContext<Acc extends Account>({
id: ID<V> | undefined, id: ID<V> | undefined,
depth: D & DepthsIn<V> = [] as D & DepthsIn<V>, depth: D & DepthsIn<V> = [] as D & DepthsIn<V>,
): DeeplyLoaded<V, D> | undefined { ): DeeplyLoaded<V, D> | undefined {
const [state, setState] = useState<{ const [state, setState] = useState<DeeplyLoaded<V, D> | undefined>(
value: DeeplyLoaded<V, D> | undefined; undefined,
}>({ value: undefined }); );
const me = React.useContext(JazzContext)?.me; const me = React.useContext(JazzContext)?.me;
useEffect(() => { useEffect(() => {
if (!id || !me) return; if (!id || !me) return;
return subscribeToCoValue(Schema, id, me, depth, (value) => { return subscribeToCoValue(Schema, id, me, depth, (value) => {
setState({ value }); setState(value);
}); });
}, [Schema, id, me]); }, [Schema, id, me]);
return state.value; return state;
} }
function useAcceptInvite<V extends CoValue>({ function useAcceptInvite<V extends CoValue>({

View File

@@ -15,6 +15,70 @@ export const subscriptionsScopes = new WeakMap<
const TRACE_INVALIDATIONS = false; const TRACE_INVALIDATIONS = false;
let nSeconds = 1;
setInterval(() => console.log(nSeconds++ + "s passed"), 1000);
export interface ThrottleOptions {
/**
* Fire immediately on the first call.
*/
start?: boolean;
/**
* Fire as soon as `wait` has passed.
*/
middle?: boolean;
/**
* Cancel after the first successful call.
*/
once?: boolean;
}
interface Throttler<T extends unknown[]> {
(...args: T): void;
cancel(): void;
}
export function throttle<T extends unknown[]>(
callback: (...args: T) => unknown,
wait = 0,
{ start = true, middle = true, once = false }: ThrottleOptions = {},
): Throttler<T> {
let innerStart = start;
let last = 0;
let timer: ReturnType<typeof setTimeout>;
let cancelled = false;
function fn(this: unknown, ...args: T) {
if (cancelled) return;
const delta = Date.now() - last;
last = Date.now();
if (start && middle && delta >= wait) {
innerStart = true;
}
if (innerStart) {
innerStart = false;
callback.apply(this, args);
if (once) fn.cancel();
} else if ((middle && delta < wait) || !middle) {
clearTimeout(timer);
timer = setTimeout(
() => {
last = Date.now();
callback.apply(this, args);
if (once) fn.cancel();
},
!middle ? wait : wait - delta,
);
}
}
fn.cancel = () => {
clearTimeout(timer);
cancelled = true;
};
return fn;
}
export class SubscriptionScope<Root extends CoValue> { export class SubscriptionScope<Root extends CoValue> {
scopeID: string = `scope-${Math.random().toString(36).slice(2)}`; scopeID: string = `scope-${Math.random().toString(36).slice(2)}`;
subscriber: Account; subscriber: Account;
@@ -48,7 +112,11 @@ export class SubscriptionScope<Root extends CoValue> {
subscriptionsScopes.set(root, this); subscriptionsScopes.set(root, this);
this.subscriber = root._loadedAs; this.subscriber = root._loadedAs;
this.onUpdate = onUpdate;
this.onUpdate = throttle((update) => {
console.log("onUpdate");
onUpdate(update);
}, 50);
this.rootEntry.rawUnsub = root._raw.core.subscribe( this.rootEntry.rawUnsub = root._raw.core.subscribe(
(rawUpdate: RawCoValue | undefined) => { (rawUpdate: RawCoValue | undefined) => {
if (!rawUpdate) return; if (!rawUpdate) return;