Wouldn't it be more performant to use something like https://github.com/angular/zone.js for dirty checking fallback instead of checking values every 120ms?
Currently mobile apps which use dirty checking fallback eating battery very quickly just because of setTimeout which checks expressions every 120ms
I'm not sure if we want to do this because:
I'll let @jdanyow chime in. We did talk about some ways that we could be more efficient with the checking a little while back though. I don't think we've implemented any improvements in this area yet.
What if we used the page visibility api and the window's focus and blur events to pause and restore dirty checking?
Page Visibility (Second Edition)
This specification defines a means for site developers to programmatically determine the current visibility state of the page in order to develop power and CPU efficient web applications.
http://caniuse.com/#feat=pagevisibility
Absolutely, we just need to fake it for browsers that don't support that. This seems like a nice little improvement.
if callback of setTimeout will be called via (ms|moz|webkit|)requestAnimationFrame (if Page Visibility API is not available) - callback will be executed only when page will be visible.
POC:
(function execOnlyIfVisible(callback, timeout){
var now = Date.now();
setTimeout(function(){
requestAnimationFrame(function(){
callback(Date.now() - now);
});
}, timeout);
})(console.log.bind(console, "I'm visible"), 5000);
Zone.js is massively hacking your browser and that approach can cause lots of side-effects.
Try to mix Angular 2 + WebComponent polyfills (maybe with Polymer on top) and you will feel massive pain. On projects we've done at my company I've observed load times of 10+ seconds when switching a view in, because of the way angular/zonejs dirty checking interacted with the MutationObserver used by webcomponent polyfill.
I hope we'll never use Zone.js in Aurelia.
I agree dirty checking is not good (for perf, battery) but you can build large, complex Aurelia applications without dirty checking at all if you're a little careful. As said in previous comments, dirty checking is only a fallback and you have several other options. That's what we're doing here, with great success.
What I would like is better diagnostics/awareness. A debug message in the console when falling back to dirty checking would be great. The problem today is that it's not hard to oversight a binding and trigger dirty checking without realizing it.
@vamp, @jods4
dirty checking is only a fallback and you have several other options
馃憤
What I would like is better diagnostics/awareness. A debug message in the console when falling back to dirty checking would be great.
When using aurelia-computed, then that is exactly what is happening.
The problem today is that it's not hard to oversight a binding and trigger dirty checking without realizing it.
Not entirely true - my app never falls back to dirty checking :)
See comment and the line in source that allows you to overwrite handler that is used when aurelia-computed is about to fall back to dirty checking :)
When using aurelia-computed, then that is exactly what is happening.
Yes, exactly. But anything that doesn't use aurelia-computed and triggers dirty checking is not logged. In fact, I don't even use aurelia-computed here...
I would love to have that debug message built into the core observation infrastructure.
Not entirely true - my app never falls back to dirty checking :)
How can you be sure, did you check?
And I'm not speaking of just aurelia-computed log; any regular binding can trigger dirty checking. So out of curiosity: _how_ did you check?
And did you check _on every single view_ of your app?
That's what we do from time to time. Usually there's nothing but occasionally something slips through.
Having some debug message would make the process a lot easier.
@jods4
And I'm not speaking of just aurelia-computed log; any regular binding can trigger dirty checking.
I've been away from FE development/Aurelia for nearly half of the year, so i may have forgotten smth...
Could You bring an example that i might have missed? If i remember correctly, Aurelia does property rewriting(or how ever it was called), so that when binding needs a property, it uses getter/setter generated by Aurelia for the property instead (that is used to intercept property changes and to avoid dirty-checking).
Regarding aurelia-computed, i replaced original handler (logging fallback to dirty-checking) with reporting + throwing an exception.
And did you check on every single view of your app?
so yes, at least regarding dirty-checking caused by getter without @computedFrom(), it is guaranteed that my app doesn't do dirty-checking (as the component doesn't work until the issue is resolved).
Could You bring an example that i might have missed? If i remember correctly, Aurelia does property rewriting(or how ever it was called), so that when binding needs a property, it uses getter/setter generated by Aurelia for the property instead (that is used to intercept property changes and to avoid dirty-checking).
Could be lots of things.
Maybe Aurelia could not rewrite the property because it was transformed into a getter/setter by another piece of code/lib;
Maybe it was frozen.
Maybe you wrote a getter and intended to use that with one-time or a signal but forgot to do so, or the property was reused at a later time in another binding.
Maybe you intended to put a @computedFrom annotation on your getter but forgot.
Another one that occured to me recently: while writing a custom attribute that wrapped a <select> I needed to listen for enabled / disabled changes in the DOM element. I was sure that Aurelia's ObserverLocator would use a MutationObserver to accomplish that, it turned out that it does not. The set of DOM properties you can observe without dirty checking is limited.
Maybe Aurelia could not rewrite the property because it was transformed into a getter/setter by another piece of code/lib;
Maybe it was frozen.
I believe I didn't use anything that would cause it.
Maybe you wrote a getter and intended to use that with one-time or a signal but forgot to do so
@jdanyow, would this be a problem that caused dirty-checking when using aurelia-computed? I thought that setter is still generated by Aurelia, that intercepts writes and notifies when property changes.
Maybe you intended to put a @computedFrom annotation on your getter but forgot.
Not a problem for me, as I was using aurelia-computed and
i replaced original handler (logging fallback to dirty-checking) with reporting + throwing an exception.
so in this case the user would see an error (and I'd receive an error report from Bugsnag) and the component just wouldn't work instead of falling back to dirty-checking.
All, I'd like to see some of the proposals here move forward and perhaps get PRs if we can reach consensus on a design. Some of the things discussed here have been frequent requests. I'm going to close this issue because we're not going to take a dep on zone.js. I've opened https://github.com/aurelia/binding/issues/562 and https://github.com/aurelia/binding/issues/563 to continue discussion on the other initiatives.
Most helpful comment
What if we used the page visibility api and the window's focus and blur events to pause and restore dirty checking?
http://caniuse.com/#feat=pagevisibility
http://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active