Skip creating snapshot clone when nobody is listening (for most updates)

This commit is contained in:
Marcel Mraz 2025-04-30 14:26:41 +02:00
parent df79ceae4e
commit 08baaa5c58
No known key found for this signature in database
GPG key ID: 4EBD6E62DC830CD2
2 changed files with 26 additions and 6 deletions

View file

@ -68,6 +68,8 @@ type MicroActionsQueue = (() => void)[];
* Store which captures the observed changes and emits them as `StoreIncrement` events.
*/
export class Store {
// internally used by history
public readonly onDurableIncrementEmitter = new Emitter<[DurableIncrement]>();
public readonly onStoreIncrementEmitter = new Emitter<
[DurableIncrement | EphemeralIncrement]
>();
@ -265,6 +267,7 @@ export class Store {
const increment = new DurableIncrement(change, storeDelta);
// Notify listeners with the increment
this.onDurableIncrementEmitter.trigger(increment);
this.onStoreIncrementEmitter.trigger(increment);
}
}
@ -325,6 +328,17 @@ export class Store {
appState: AppState | ObservedAppState | undefined,
) {
const macroAction = this.getScheduledMacroAction();
// perf. optimisation, since "EVENTUALLY" does not update the snapshot,
// so if nobody is listening for increments, we don't need to even clone the snapshot
// as it's only needed for `StoreChange` computation inside `EphemeralIncrement`
if (
macroAction === CaptureUpdateAction.EVENTUALLY &&
!this.onStoreIncrementEmitter.subscribers.length
) {
return;
}
const nextSnapshot = this.maybeCloneSnapshot(
macroAction,
elements,

View file

@ -2547,14 +2547,19 @@ class App extends React.Component<AppProps, AppState> {
});
}
this.store.onStoreIncrementEmitter.on((increment) => {
if (StoreIncrement.isDurable(increment)) {
this.store.onDurableIncrementEmitter.on((increment) => {
this.history.record(increment.delta);
}
this.props.onIncrement?.(increment);
});
const { onIncrement } = this.props;
// per. optimmisation, only subscribe if there is the `onIncrement` prop registered, to avoid unnecessary computation
if (onIncrement) {
this.store.onStoreIncrementEmitter.on((increment) => {
onIncrement(increment);
});
}
this.scene.onUpdate(this.triggerRender);
this.addEventListeners();
@ -2614,6 +2619,7 @@ class App extends React.Component<AppProps, AppState> {
this.eraserTrail.stop();
this.onChangeEmitter.clear();
this.store.onStoreIncrementEmitter.clear();
this.store.onDurableIncrementEmitter.clear();
ShapeCache.destroy();
SnapCache.destroy();
clearTimeout(touchTimeout);