Skip to content

Commit 05a702c

Browse files
committed
perf: state changer will not actually call callbacks if state value has not changed
1 parent 9e16f18 commit 05a702c

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

src/state_handler.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
import _ from 'lodash';
2+
13
const create_state_handler = () => {
24
const state = {}
35
let subscriptions = []
46

5-
const handle_change = () => {
7+
const update_state = (variable, value) => {
8+
// Replace old state with new state, report if value has actually changed
9+
const old_state = Object.assign({}, state)
10+
state[variable] = value
11+
if (_.isEqual(old_state, state)) return false
12+
return true
13+
}
14+
15+
const handle_change = (variable, value) => {
16+
// Return early if state didn't actually change
17+
if (!update_state(variable, value)) return
618
const old_subscriptions = subscriptions.slice()
719
subscriptions = []
820
old_subscriptions.map(callback => callback(state_handler, callback))
@@ -12,13 +24,11 @@ const create_state_handler = () => {
1224
'get_state': () => state,
1325
'init_variable': (variable, value) => {
1426
if (state[variable] === undefined) {
15-
state[variable] = value
16-
handle_change()
27+
handle_change(variable, value)
1728
}
1829
},
1930
'set_variable': (variable, value) => {
20-
state[variable] = value
21-
handle_change()
31+
handle_change(variable, value)
2232
},
2333
'subscribe': (callback) => {
2434
subscriptions.push(callback)

src/state_handler.test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ describe('state handler', () => {
8181
my_callback.should.be.calledWith(state_handler, my_callback)
8282
})
8383

84+
it(`callback should not be called when no actual change happens - ${method}`, () => {
85+
const my_callback = sinon.spy()
86+
const injector = require('inject-loader!./state_handler.js')
87+
const state_handler = injector({
88+
'lodash': {'isEqual': () => true}
89+
}).default()
90+
state_handler.subscribe(my_callback)
91+
state_handler[method]('foo', 42)
92+
my_callback.should.not.be.called()
93+
})
94+
8495
it(`callback should retrieve collect state - ${method}`, () => {
8596
let retrieved_state = null
8697
const my_callback = (handler) => {
@@ -112,7 +123,10 @@ describe('state handler', () => {
112123

113124
it('callback should be called again with re-subscribe', () => {
114125
const my_callback = sinon.spy(function() {state_handler.subscribe(my_callback)})
115-
const state_handler = create_state_handler()
126+
const injector = require('inject-loader!./state_handler.js')
127+
const state_handler = injector({
128+
'lodash': {'isEqual': () => false}
129+
}).default()
116130
state_handler.subscribe(my_callback)
117131
state_handler.set_variable('foo', 42)
118132
state_handler.set_variable('foo', 42)

0 commit comments

Comments
 (0)