Batching โ
Batching allows to invoke reactions/effects โ only once, for changes that were made almost at the same time.
INFO
Functions provided to subscribe, autorun, or observer are collectively known as Reactions/Effects โ they react to changes in observables and re-execute when dependencies are updated.
How it works โ
Letโs make some preparations before we get into how it works.
import { Observable, listen, subscribe } from 'kr-observable'
class State extends Observable {
a = 1
b = 1
c = 1
}
const state = new State()
// should be invoked when a, b or c changes
function subscriber() {
console.log('run reaction ๐')
}
// will log all changes is state
function listener(property) {
console.log(property, ' was changed')
}
listen(state, listener)
subscribe(state, subscriber, new Set(['a', 'b', 'c']))
// will emulate async requests
function delay() {
return new Promise((resolve) => {
setTimeout(() => resolve(2), 50)
})
}Now weโll change state in different ways to understand and control ยซbatchingยป.
INFO
Here changes are made at same time, and reaction will run once:
function change() {
state.a = 2
state.b = 2
state.c = 2
}
change()Console output:
a was changed
b was changed
c was changed
run reaction ๐INFO
Here changes are made in an async function with await statement, but since changes starts after promise is resolved, they are made at same time, and effect will run once:
async function change() {
state.a = await delay()
state.b = 2
state.c = 2
}
change()Console output:
a was changed
b was changed
c was changed
run reaction ๐INFO
Here changes are made in an async function with more than one await statement during assignment:
async function change() {
state.a = await delay()
state.b = await delay()
state.c = 2
}
change()Console output:
a was changed
๐ฅ๐ฅ run reaction ๐
b was changed
c was changed
run reaction ๐Why effect was invoked twice in last example?
Thatโs because assignment value to property b, was deferred by await statement to the next tick, but changes are considered made at the same time, if they happen in the same tick.
Control batching โ
Now that we understand how batching works, we can easily control it. We just wait until promises resolves, and then make changes:
async function change() {
const a = await delay()
const b = await delay()
state.a = a
state.b = b
state.c = 2
}
change()Console output:
a was changed
b was changed
c was changed
run reaction ๐TIP
Nothing break if you wonโt control batching, but knowledge how it works, can help you, for example, to reduce the number of unnecessary renders in React to zero.