-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is there a way to debounce computed functions? #48
Comments
Hi @dzearing, There is indeed a transaction mechanism, in your case it would look like: mobservable.transaction(() => {
a = 1;
b = 1;
}); To achieve the desired effect; e.g. recompute Further note that If you don't observe |
I see. The transaction support is great and that feels super useful. It would be nice to have computed function evals be optionally throttled to prevent chatty situations, even when there are observers. I guess we could do this like so: @observable get title() {
throttle(() => {
this._lastTitle = this.a + this.b;
}, 1000);
return this._lastTitle;
} However this isn't really desired. If someone gets title, it should be synchronously resolved. In the example above, accessing title will return the old value rather than the new. If a and b mutate, we simply want the observers to be notified when N idle time has passed. I think this has to be provided at the notifier layer. Something like: @observable({ throttle: 1000, rateLimit: 2000 }) get title() { ... } |
There is an /**
* Once the view triggers, effect will be scheduled in the background.
* If observer triggers multiple times, effect will still be triggered only once, so it achieves a similar effect as transaction.
* This might be useful for stuff that is expensive and doesn't need to happen synchronously; such as server communication.
* Afther the effect has been fired, it can be scheduled again if the view is triggered in the future.
*
* @param view to observe. If it returns a value, the latest returned value will be passed into the scheduled effect.
* @param the effect that will be executed, a fixed amount of time after the first trigger of 'view'.
* @param delay, optional. After how many milleseconds the effect should fire.
* @param scope, optional, the 'this' value of 'view' and 'effect'.
*/
export function autorunAsync<T>(view: () => T, effect: (latestValue : T ) => void, delay:number = 1, scope?: any): Lambda { Using this is a bit more verbose / ugly then your proposal, it is an interesting proposal. On the other hand, it might be very powerful as well to just provide interoperability with RxJs (which should be quite easy to achieve), because that library already provides excellent support for time controlled observable values. |
I was trying to use var array = mobservable.observable([])
array.push({ keys1: {1: true}})
array.push({ keys2: {2: true}})
array.observe((changes) => {
console.log('changes in array:', changes);
});
mobservable.transaction(() => {
var obj = array.splice(0, 1)[0];
array.push(obj);
});
// 'changes in array' logs twice |
Hi @sunny-g Transaction only works for |
Hey @mweststrate, ahh, makes sense. As it turns out, the |
Closing this issue for now, might need re-evaluation after implementing #57. |
#57! I was planning on incorporating RxJS observables for just one part of my code (I have multiple consecutive websocket messages coming in, both mutate the same mobservable, but I want them combined into one atomic action so they only mutate the mobservable once). I don't think it makes any sense to wrap my socket message handler into a Based on what I've proposed, is this something I can do with mobservable as is, or would I need RxJS? |
You can build some manual debounce around mobservable, but personally I would use RxJS indeed, apply the debouncing etc and then observe the resulting stream to update the mobservable data. For anything that involves working with time such as throttling, or which involves combining multiple events from the same stream (and not just the latest) I would use RxJs which provides the more low level primitives. For everything else, and especially for storing app state, I would use Mobservable which is IMHO more convienient and high level to work with. |
Thank you for your input, I'm really glad to hear I'm not using mobservable and RxJS incorrectly while also reinventing the wheel :) |
Say I have a computed observable:
If I assign both a and b:
Then computeTitle is called 2 times. This is a waste and definitely adds up in bulk usage. I would like it to be called once, or on demand if it's needed. E.g.
Then... right before we update react observer components, if there are observers of a dirty computed, we evaluate it so that we can know if we need to tell the observers.
In Knockout, I think there are 2 tools to deal with this. Pure computeds can be used for scenarios like this where there are no side effects of the function being called. If nobody accesses their value, I believe they don't even calculate. I could be wrong though.
Rate limiting is another tool to prevent chatty observables from causing redundant re-evaluations of computed.
Both have their purposes.
Is there anything in mobservable for this? I'd love by default that computed functions do the optimal thing and that you have to do extra work to do suboptimal things (like have the function called on every granular re-evaluation.)
I have heard that there are transactions you can do around assigning multiple things to avoid redundant computes, but didn't find docs on it and haven't dug through the code yet.
The text was updated successfully, but these errors were encountered: