Skip to content
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

Performance enhancement feature: Item groups #11

Merged
merged 6 commits into from
Jul 29, 2018

Conversation

TAGC
Copy link
Contributor

@TAGC TAGC commented Jul 8, 2018

Introduces an "item group" feature that can potentially improve performance for certain use cases of this library.

Motivation

In some cases the collection you pass to a VirtualCollection might contain logically separate types of items that change at different rates. For example, in my case I use VirtualCollection to represent a 2D cartesian grid-space, with two types of objects used in the collection:

  • grid tiles
  • grid items

Grid items are arbitrary objects displayed on the grid. These are passed to the grid as props and so depend entirely on the application consuming my library. The collection of grid items may change frequently. On the other hand, grid tiles are controlled entirely by my grid library and only need to be changed ("regenerated") when the grid is resized.

As vue-virtual-collection currently treats all items in the collection equally, it will invoke cellSizeAndPositionGetter, register cells, etc. for every single item in the collection whenever a single item changes. Consider a case where a 100x100 grid is created and 10 grid items are placed on it. If a single grid item changes, VirtualCollection will perform this procedure for all 10,000 tiles and 10 grid items even though only a single grid item has changed.

However, with the concept of "item groups" I can pass grid tiles and grid items to VirtualCollection as separate groups, and when an item changes VirtualCollection will only process the group that contains that item. In this scenario, when a grid item changes it cuts the number of elements operated on from 10,010 to just 10, a reduction of ~99.9%. This can help significantly improve performance.

Implementation

Clients of this library can opt-in to using groups by passing an array of objects with the form { group: [...] }, where [...] represents the items of the collection belonging to a specific group. In the scenario given above, :collection="[...tiles, ...items]" would get replaced with :collection="[ { group: [] }, { group: [] } ]", where the first array would be updated to contain the tiles and the second to contain the grid items.

Internally, VirtualCollection creates separate watchers for each group in the collection, so that any changes that are limited to a specific group of items will only cause the watcher for that group to fire.

This feature does not present breaking changes - it is still possible to pass a flat array of items to :collection, in which case it gets wrapped as a single group. This means that all existing usages of the library should work as before, without significant changes in performance. I have confirmed this is the case with my library, and all existing unit tests continue to pass.

Benchmarks

Below is a comparison of the performance changes introduced for a demo project based on my grid library, which in turn depends on vue-virtual-collection. The profiles shown below were captured in Chrome devtools on a mid-2014 MacBook Pro running macOS High Sierra 10.13.5. For both profiles, I keep the grid stationary (so that tiles don't regenerate), so that only the grid items change.

Over the course of a second, I observe a reduction in scripting time from 191.4ms to 107.5 ms, a ~44% decrease.

Without Item Grouping

Without item grouping

With Item Grouping

With item grouping

TAGC added 4 commits July 1, 2018 16:50
These changes make it so that the collection of cells used by section
managers gets frozen after cells have been registered, which
improves performance when calculating display items.
@TAGC
Copy link
Contributor Author

TAGC commented Jul 8, 2018

Not sure why but the tests are failing during the CI build. They pass on my machine using identical versions of nvm, npm and node.

@starkwang
Copy link
Owner

Sorry for my delay😔. I will review this PR today and try to fix the tests.

Thanks a lot!

Copy link
Owner

@starkwang starkwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
Could you add some documents for the new group feature ?

@starkwang
Copy link
Owner

The broken test seems a little bit flaky and it can be reproduced on linux.
I will merge this PR after fixing the flaky test.

@TAGC
Copy link
Contributor Author

TAGC commented Jul 27, 2018

@starkwang Cheers, glad you could test it on your machine to help narrow down where the issue lies.

@TAGC
Copy link
Contributor Author

TAGC commented Jul 27, 2018

And sure, I'll create the documentation later on today or this weekend.

totalWidth: 0
totalWidth: 0,
displayItems: [],
groupManagers: []
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The groupManagers doesn't need to be bind. Can you move it to the created() method ? This can fix the flaky test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to have worked, thanks.

Moves the `groupManagers` property of `VirtualCollection` out of the
data object to prevent Vue making it reactive.

This may help resolve a flaky unit test when running on Linux.
@TAGC
Copy link
Contributor Author

TAGC commented Jul 28, 2018

Before this gets merged, would you me to commit the stuff under dist/?

https://prnt.sc/kc4owd

@starkwang
Copy link
Owner

@TAGC Thanks for contribution!

You don't need to commit the stuff under dist/. They will be build automatically before publishing the new version of npm package.

@starkwang starkwang merged commit a53d4e1 into starkwang:master Jul 29, 2018
@TAGC TAGC deleted the feature/groups branch July 29, 2018 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants