Hi, I have written and app for a small portable devices (watch) that requires very low background CPU and processing usage. I’ve been trying to optimise this and using the browser debug timeline I can see that the Aurelia binding engine is calling all subscribers every seconds or so when the screen is off as I think the browser is throttling the timers. Under predefined scenarios like document.visibility = “hidden” I want to suspend the binding engine, or at least throttle the binding engine/subscriptions to update every x seconds. Obviously I only want the last change to be called when the screen comes on. I’ve played around with throttling the flushTaskQueue and flushMicroTaskQueue (just a hack test) but this does not seem to be the way to go. Can anyone point me to a way of achieving this? could it be done with a plugin? Even some pointers on where I should look to inject some code as flushQueues does not seem to be the way forward here.
Oh, and i don’t want to add throttle/denounce to all bindings as it needs to be dynamic. Unless there is a way I can dynamically apply a throttle to all my bindings in code maybe…?
By default, changes are only notified when there’s something that … has been changed. I guess there’s something in the app that triggers dirty checking, causing it to be constantly firing. Maybe have a check? Normally it can comes from either:
getter without @computedFrom
binding to an element property that Aurelia doesn’t know how to observe
You can also use this plugin https://github.com/jdanyow/aurelia-computed to automatically handle your computed property. Though I’d say it’s still better that you check it carefully.
There’s no dirty checking at all, I’ve made sure of this. And I am using @computedFrom appropriately. The problem is that the @computedFrom properties are being updated when the screen is off, and hence the binding in the dom. I don’t want the dom updates to run when the screen is off, and only the last property update to be applied when the screen comes on again.
I get I could add a @computedFrom(‘signalSwicth’) and flip the switch only when I want updates to occur, but I’m looking for a way to do this globally.
This is the part where it doesn’t make sense. Computed properties are constantly read whenever there’s something that constantly needs to read it. And if you’ve made sure that all getters are decorated with @computedFrom, then I think there’s some setInterval floating somewhere in your app, or the plugins that your app uses.
Can you put a breakpoint inside those getters, and see what’s calling it?
Ok, maybe I’m not explaining properly. I’ll try again. I have a background task that updates my model properties every 1 second. I also have a view bound to this model. So when the background task updates the model properties, Aurelia then updates the view where I’ve bound to these properties. I will continue to run my background task and update the model every 1 second, but I want to tell Aurelia to suspend all updates of the view and not reflect the model changes when the screen is off, or if say xx seconds elapsed since last update. I hope this makes sense?
There’ 3 types of flow here, despite all are in the “view”:
view model <-> view (<input/>)
view model <-> model (<some-el/>)
view model -> view model (one way with <some-el/>)
What will happen to the 2nd & 3rd one? Note that if it’s 2 way binding, suspended flow in one way may also stop the other.
We can go 1 step further and stop it from handling change notifications from source if needed, but that’s a bit more involved. Maybe try the above first and do some more monitoring?
Edit: Can also check if target is a DOM element then stop updating, else keep the value flow.
wow, thank you! Amazing work, it looks the goods… I’ll give this a go and let you know how it goes. I use Aurelia on several projects but don’t have this level of understanding of the inner workings as yet. I really appreciate the detail. Cheers
So far this seems to be working as expected but I have a little more testing to do as yet… here’s a question on this, when the screen visibility changes to visible is it possible to ‘flush’ the last update to the dom ? I’m looking to get the most recent property change to the dom, and not rely on it changing within the last second via my background task as not all properties will be updated every second.
I was able to reason about the code in your earlier post where you defined the pauseUpdateTarget and resumeUpdateTarget instance methods for the View class and used those in the AppRoot‘s created lifecycle hook. Very interesting. But I fail to see how your `flushChanges’ instance method in your latest post is intended to work.
Does it replace an existing implementation of a flushChanges instance method of the View class? Regrettably, I was unable to locate such a method in Aurelia’s source code for the View class (in /src/view.js in the aurelia-templating package). I did notice some flushChanges method implementations in some accessor and observer classes in the @aurelia/runtime-html package, but that package seems to be an Aurelia vNext package.
But if the flushChanges method does not already exist in the View class, I assume it could be considered to be an additional “custom” instance method of the View class? But how and when should it be used/called in that case? I currently do not understand how and when it gets called.
Or am I perhaps looking in the wrong places in the source code? Or do I need to investigate Aurelia’s internal mechanisms in some more detail to understand how this code is supposed to work?
Thanks in advance.
Edit: Sorry… Just re-read @Devron’s latest post. So it is intended to be called when screen visibility is changed to visible.
@Devron use case is very interesting, and for the example code above, I think we can push it further, like this:
if binding target is not a DOM element, then proceed update
if binding is not paused, proceed update
This will make the data flow throw the entire app, without updating any UI pieces, and should be extremely performant if you want to propagate changes down to leaf components for some side effects, maybe
This is exactly how I’ve applied this, but I’ve been slightly distracted with other priorities. I’ll be doing more testing on this soon. Thanks again for all your help so far!