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

Ability to disable reactivity to improve performance on destroy - On 2.6.* #3808

Closed
bryarb opened this issue Nov 25, 2022 · 2 comments
Closed

Comments

@bryarb
Copy link

bryarb commented Nov 25, 2022

What problem does this feature solve?

Destroying N RouterLink at once has a cost of O((N^2)/2) due to all RouterLink depend on the singleton reactive property $route. When removing hundreds or thousands of links from the page, this cost is noticeable, especially on slow devices. The goal is a cost of O(N).

Hundreds or thousands of links might seem too much, but sure there might be some cases where it makes sense, like an infinite scroll or some big grids. In many cases vue-virtual-scroller should solve the general problem, but I think it would be better not to require it as a rule.

Removing the dependency on $route means effectively disabling reactivity for the RouterLink and thus all the related features. At this moment, I think the only affected features are the CSS classes to show a link is active.

Why this cost?

The singleton _route is created for the _routerRoot once. At this moment, Vue instantiates a Dep to track writes and reads on this attribute.

Each time a RouterLink is created, its render Watcher detects the $route is accessed, so that the Watcher adds the Dep to its dependencies (Watcher.deps) and the Dep adds the Watcher to its subscribers (Dep.subs). This means the Dep.subs for _route is, at least, as large as the number of rendered RouterLinks.

When the $route changes, all the RouterLink are updated because they are on the Dep.subs.

When destroying all the RouterLink (page change), all the components teardown their watchers, and each watcher have to remove itself from the Dep.subs. Removing a single RouterLink's Watcher from the Dep.subs costs O(N - i), where N is the number of RouterLink and i the number of RouterLink already removed.

Generally speaking, the cost of removing N RouterLinks at once is O((N^2)/2).

What does the proposed API look like?

Adding a no-reactive prop on RouterLink should be enough.

The meaning of this prop is effectively disabling reactivity on the current route to improve the overall performance, especially when destroying many RouterLink at once.

As a side effect, this flag turns off any feature that depends on the current route. At this moment, I think the only affected features are related to the CSS classes to show if a link is active or not.

ORIGINAL LINK: #3500 (comment)

@bryarb
Copy link
Author

bryarb commented Nov 25, 2022

Please dont close this so I can put a bounty here of 500$:
https://app.bountysource.com/issues/114008264-ability-to-disable-reactivity-to-improve-performance-on-destroy-on-2-6
I need this fixed with a 2.6.* tag not 2.7.* or else I need to rewrite my entire website

@posva
Copy link
Member

posva commented Nov 25, 2022

Unfortunately, as noted at #3500 (comment), the change needed would be to use Sets() instead of Arrays. The reason Vue 2 doesn't use them is to support IE without polyfills. That's also why Vue 3 doesn't have that limitation. In other words, if you want to fix this you will have to:

  • Not support IE
  • Create a local patch to use Set instead of arrays within vuejs/core

This can't be fixed in router's code unless a new component is added but this won't happen for an edge case that isn't an issue in newer versions anymore. So even if someone gets the fix done, it won't get released, probably blocking them from getting the bounty. Instead, the person can contact you to get paid for the feature as a patch with https://www.npmjs.com/package/patch-package without us getting involved in such a transaction.

BTW Vue 2.7 is backwards compatible with Vue 2.6, so you should be able to upgrade. Any other bug fixes will happen in 2.7 not in 2.6

@posva posva closed this as not planned Won't fix, can't repro, duplicate, stale Nov 25, 2022
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

No branches or pull requests

2 participants