-
Notifications
You must be signed in to change notification settings - Fork 108
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
Fixed row height optimization #221
base: fixed-height-optimization
Are you sure you want to change the base?
Fixed row height optimization #221
Conversation
@@ -64,6 +64,11 @@ <h1 class="page-header">Scroller Examples</h1> | |||
Bottom visible (Adapter) | |||
</a> | |||
</li> | |||
<li> | |||
<a href="fixedRowHeight/fixedRowHeight.html"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added demo, after npm start
it is available as http://localhost:5005/fixedRowHeight/fixedRowHeight.html
|
||
// PHIL: Provide a fixed row height | ||
// | ||
const rowHeight = parseNumericAttr($attr.rowHeight, null, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switched to camelcase, which means row-height="20"
usage
src/ui-scroll.js
Outdated
@@ -386,8 +397,11 @@ angular.module('ui.scroll', []) | |||
// We need the item bindings to be processed before we can do adjustments | |||
!$scope.$$phase && !$rootScope.$$phase && $scope.$digest(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@priandsf This is the bottleneck of the new demo (http://localhost:5005/fixedRowHeight/fixedRowHeight.html). And this $digest can't be removed, it responses for manual data-binding and transforming a row template into final html with all the data and handlers. Running the demo, you'll see that removing this $digest breaks the demo app.
From the other hand, I didn't see any significant difference in the performance with and without rowHeight (if don't touch this $digest). Probably the demo is not good, and I would ask you to update it if you can. The demo must show a difference with and without rowHeight. But if this particular $digest is the only call that "can" improve situation, then I would say probably we are on the wrong way. I don't see a situation where this $digest can be removed.
So, please look at the demo, try to reproduce performance changing and let me know, what do you think. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you're right, commenting $digest in processUpdates()
was too aggressive. It worked in my case as we had another trigger for $digest. I suspect this was not good :-)
I split the behavior into row-height
and allow-visibility-watch
, as they target 2 different use cases. I added the latest to the fixed row demo page (thanks for that one!) and it seems to work properly. Our use case is very similar to what this page shows, with a repeat within the row. Good guess!!
For resizeAndScrollHandler()
, why are we forcing a $digest in the first place? When it does not update the DOM (handled by enqueueFetch
), then it should just be a simple native scroll, shouldn't it? It is still conditioned by rowHeight
, but I'm not sure that this is right :-)
I pushed that code to my branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@priandsf Answering to your question, I'm not sure about resizeAndScrollHandler $digest, I need some time to investigate it. But the question I would like to consider before is what we are going to improve? Browser reflow problem resulting from element.height()
and maybe something else related to direct DOM manipulations OR $digest things? The answer is mostly important and requires demo-proof. I think we should not optimize things that really don't affect the performance. You know easier code could be more valuable than performant code, in case its performance bonus is negligible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough - So far, resizeAndScrollHandler()
in my app takes ~10ms, with most of the time within $digest when I scroll up and down without loading data. This can be higher when the GC is triggered. This is on a macbook pro running the latest Chrome. I haven't tried on other browsers yet...
So it doesn't feel laggy with this configuration. Up to you if you want/can remove the $digest.
Overall, the optimizations really made it smoother, thanks a lot for all your efforts. This library rocks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@priandsf I have an answer on why do we need $digest in the end of resizeAndScrollHandler
: it is needed for triggering topVisible and bottomVisible properties changing (after they are calculated by calculateProperties
method) on the outer scope (top-visible="..."
) and to the outer scope adapter (adapter.topVisible
). And we have two tests covering some of the correspondent use cases (this and this): they fail when that $digest is removed. And it does not depend on rowHeight. So when that $digest is removed, the assignments itself do work (scope and adapter props are being updated properly), but $watch
does not work. The tests I just mentioned are about it.
One of the possible solutions is to html attribute for disable top/bottomVisible properties calculation/propagation + maybe adapter methods to enable/disable this feature runtime, and even the adapter method to calculate top/bottomVisible data immediately. So, users that don't need top/bottomVisible data (or don't need it right now) can switch this functionality off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the investigation, that makes sense. The flag will work for me, although it might complicate the developer experience as understanding the attribute requires a deep knowledge of the internals. Based on our performance result, it is fine for me if we postpone that change.
Are you willing to merge the other ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhilt I believe I got a solution for the $digest: the adapter checks if the directive has any of these attributes (top-visible, ...) defined and publishes it as a public property. Then the ui-scroll checks this property to know if it has to trigger the $digest.
I pushed the change to my branch. The unit tests and the demo (topVisible+topVisibleAdapter) work properly with this change. Let me know what you think!
…h=false" to the fixed scroll demo, for now...
wrapper.unregisterVisibilityWatcher = wrapper.scope.$watch(() => visibilityWatcher(wrapper)); | ||
} | ||
if (!rowHeight) { | ||
if (allowVisibilityWatch) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This particular case, I mean hiding the elements before data binding, is not related to visibility-watcher. I would say that it may relate to rowHeight. We are hiding new rows before data binding, because the height might change after binding, and there could be some bad side effects (scroll bar shifting). And we may not hide new rows if we know that the height is not going to be changed.
@@ -397,7 +400,7 @@ angular.module('ui.scroll', []) | |||
// We need the item bindings to be processed before we can do adjustments | |||
!$scope.$$phase && !$rootScope.$$phase && $scope.$digest(); | |||
|
|||
if (!rowHeight) { | |||
if (allowVisibilityWatch) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Showing new rows after binding relates to hiding new rows before binding. So it does not relate to visibility-watcher, it may relate to rowHeight (see previous comment).
@dhilt We are intensively testing this optimization and found an issue with the => How it manifests: => Why it behaves like this: => Why it works with the visibility watcher I'm not sure what
But checking Any idea? |
@priandsf There was the issue years ago (angular-ui/ui-utils#239) and it was fixed with PR Hill30/NGScroller#39, which is responsible for wheelHandler code. We also have demo http://localhost:5005/scrollBubblingPrevent/scrollBubblingPrevent.html and test case ("prevent unwanted scroll bubbling"). Well, I took v1.7.4, commented out
line and run the demo app. And I didn't see your problem with Mac's track pad (wheelHandler did work). I will try to reproduce your issue, but at first glance it's not so obvious, and it would be helpful if you might say how to reproduce it with minimal changes over the latest version (1.7.4). |
@dhilt Ok I narrowed down the problem in our app. I cannot reproduce it yet on one of the samples ;-( To make a long story short, it happens because Nevertheless, I checked-in a fix that makes it works in our case: when |
# Conflicts: # dist/ui-scroll-grid.js # dist/ui-scroll.js # dist/ui-scroll.js.map # dist/ui-scroll.min.js # dist/ui-scroll.min.js.map # src/modules/buffer.js # src/modules/padding.js # src/modules/viewport.js # src/ui-scroll.js
@dhilt Hi Denis, I'll be happy if you can have a look at the row-height. I put many optimizations into it:
|
@dhilt I uploaded our latest code to my branch if you want to give a look. We did sone extensive testing on our application and we haven't found any major issue. |
@priandsf I will take a look when I have time, especially I think I'm most excited about the performance demo! |
Based on issue #220.