Skip to content

Commit

Permalink
perf: Only trigger a state change if the state is definitely different (
Browse files Browse the repository at this point in the history
  • Loading branch information
dermotduffy authored Sep 22, 2024
1 parent 716a33f commit a4417e8
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 2 deletions.
12 changes: 10 additions & 2 deletions src/card-controller/conditions-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
import { HassEntities } from 'home-assistant-js-websocket';
import { isEqual } from 'lodash-es';
import merge from 'lodash-es/merge';
import { ZodSchema } from 'zod';
import {
Expand All @@ -10,10 +11,10 @@ import {
} from '../config/management';
import {
FrigateCardCondition,
RawFrigateCardConfig,
ViewDisplayMode,
frigateConditionalSchema,
Overrides,
RawFrigateCardConfig,
ViewDisplayMode,
} from '../config/types';
import { desparsifyArrays } from '../utils/basic';
import { CardConditionAPI, KeysState } from './types';
Expand Down Expand Up @@ -227,6 +228,13 @@ export class ConditionsManager {
}

public setState(state: Partial<ConditionState>): void {
// Performance: Compare the new state with the existing state and only
// trigger a change if the new state is different. Only the new keys are
// compared, since some of the values (e.g. 'state') will be large.
if (Object.keys(state).every((key) => isEqual(state[key], this._state[key]))) {
return;
}

this._state = {
...this._state,
...state,
Expand Down
54 changes: 54 additions & 0 deletions tests/card-controller/conditions-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,60 @@ describe('ConditionsManager', () => {
expect(manager.getState()).toEqual(state);
});

describe('should set state', () => {
it('should set and be able to get it again', () => {
const state = {
fullscreen: true,
};

const manager = new ConditionsManager(createCardAPI());

manager.setState(state);
expect(manager.getState()).toEqual(state);
});

it('should set but only trigger when necessary', () => {
const state_1 = {
fullscreen: true,
state: {
'binary_sensor.foo': createStateEntity(),
},
};

const listener = vi.fn();
const manager = new ConditionsManager(createCardAPI(), listener);

manager.setState(state_1);
expect(listener).toBeCalledTimes(1);

manager.setState(state_1);
expect(listener).toBeCalledTimes(1);

manager.setState({ fullscreen: true });
expect(listener).toBeCalledTimes(1);

manager.setState({
state: {
'binary_sensor.foo': createStateEntity(),
},
});
expect(listener).toBeCalledTimes(1);

manager.setState({ fullscreen: false });
expect(listener).toBeCalledTimes(2);

manager.setState({ fullscreen: false });
expect(listener).toBeCalledTimes(2);

manager.setState({
state: {
'binary_sensor.foo': createStateEntity({ state: 'off' }),
},
});
expect(listener).toBeCalledTimes(3);
});
});

describe('should handle hasHAStateConditions', () => {
beforeEach(() => {
vi.spyOn(window, 'matchMedia').mockReturnValueOnce({
Expand Down

0 comments on commit a4417e8

Please sign in to comment.