perf: Only trigger a state change if the state is definitely different (#1569)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
|
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
|
||||||
import { HassEntities } from 'home-assistant-js-websocket';
|
import { HassEntities } from 'home-assistant-js-websocket';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
import merge from 'lodash-es/merge';
|
import merge from 'lodash-es/merge';
|
||||||
import { ZodSchema } from 'zod';
|
import { ZodSchema } from 'zod';
|
||||||
import {
|
import {
|
||||||
@@ -10,10 +11,10 @@ import {
|
|||||||
} from '../config/management';
|
} from '../config/management';
|
||||||
import {
|
import {
|
||||||
FrigateCardCondition,
|
FrigateCardCondition,
|
||||||
RawFrigateCardConfig,
|
|
||||||
ViewDisplayMode,
|
|
||||||
frigateConditionalSchema,
|
frigateConditionalSchema,
|
||||||
Overrides,
|
Overrides,
|
||||||
|
RawFrigateCardConfig,
|
||||||
|
ViewDisplayMode,
|
||||||
} from '../config/types';
|
} from '../config/types';
|
||||||
import { desparsifyArrays } from '../utils/basic';
|
import { desparsifyArrays } from '../utils/basic';
|
||||||
import { CardConditionAPI, KeysState } from './types';
|
import { CardConditionAPI, KeysState } from './types';
|
||||||
@@ -227,6 +228,13 @@ export class ConditionsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setState(state: Partial<ConditionState>): void {
|
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 = {
|
||||||
...this._state,
|
...this._state,
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -429,6 +429,60 @@ describe('ConditionsManager', () => {
|
|||||||
expect(manager.getState()).toEqual(state);
|
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', () => {
|
describe('should handle hasHAStateConditions', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.spyOn(window, 'matchMedia').mockReturnValueOnce({
|
vi.spyOn(window, 'matchMedia').mockReturnValueOnce({
|
||||||
|
|||||||
Reference in New Issue
Block a user