vanjs-org / van

🍦 VanJS: World's smallest reactive UI framework. Incredibly Powerful, Insanely Small - Everyone can build a useful UI app in an hour.
https://vanjs.org
MIT License
3.89k stars 92 forks source link

State change debounce and supression #46

Open efpage opened 1 year ago

efpage commented 1 year ago

For my understanding, state management in VanJS is event driven. The event is triggered by the state setter and prpagated to all event listeners:

s.listeners.forEach(l => l(v, curV))

For frequent updates this may cause too many calls. A common way to prevent this is a timeout, that prevents retriggering before the timeout has fired.

It may also be useful to have an option to globally disable all events (e.g. during page update or deletion) programmatically with frunctions like van.inhibitUpdate() and van.restoreUpdate().

Tao-VanJS commented 1 year ago

I feel that the suppression logic can be implemented in event handlers instead of VanJS library.

efpage commented 1 year ago

Not sure how to do this. Any suggestion welcome.

Let assume, there are 50 state objects, each changed 500 times per second on an irregular basis. But we want the UI to update only once per second. So we need to inhibit the event propagation, but still remember that the state object was changed. After one second, we want all state objects to fire, if the state was changed in the meantime.

I agree that it is not desired to put this in the core library, but maybe there could be an entry point to apply this kind of logic externally? Something like a event-function (onStateChanged)?

Tao-VanJS commented 1 year ago

I think the following design pattern can solve your problem:

const appState = ...
const viewState = {
  prop1: van.state(...),
  prop2: van.state(...),
  ...
}

setInterval(() => {
  <Sync `appState` to `viewState`>
}, 1000)

const App = div(
  ...
  // Inside your application, we bind DOM nodes to `viewState`, but only mutate `appState`
  // to handle the state changes.
)
efpage commented 1 year ago

It seems, VanJS already contains all it needs:

18:  if (s.oldVal === curV)
19:     changedStates = addAndScheduleOnFirst(changedStates, s, updateDoms,  updateRate);

I added "updateRate" here with an initial value of zero. If I change this to a larger value, updates slow down, but are not skipped. So, adding this value and a setter could simply be enough to prevent event blocking.

efpage commented 1 year ago

I made a demo to show the issue with state blocking. This creates 1000 div´s showing different states. This is updating every 1/100 second which may run fluently on a fast machine. But if you increase the number n to 10.000, this starts to slow down your machine.

You can use a slider to reduce the update rate so see the effect.

This demo uses a modified version of VanJS including the simple solution mentioned above.

Check out on flems.io