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, ' where 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 were changed
b were changed
c were 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 were changed
b were changed
c were 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 were changed
๐ฅ๐ฅ run reaction ๐
b were changed
c were 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 were changed
b were changed
c were 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.