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

v-model is slow (hangs) when used on a big select[multiple] element #10014

Closed
4refael opened this issue Jan 5, 2024 · 5 comments
Closed

v-model is slow (hangs) when used on a big select[multiple] element #10014

4refael opened this issue Jan 5, 2024 · 5 comments

Comments

@4refael
Copy link

4refael commented Jan 5, 2024

Vue version

3.4.5

Link to minimal reproduction

https://play.vuejs.org/#eNqNUk1v2zAM/SuCLt2Axg6W9eKlQbehh+2wDetuVQ+ZzcRq9QWJdlIY/u+jpCX1sqLoTSQfHx+fOPCPzhV9B7ziy1B76ZAFwM6thJHaWY9sYB42bGQbbzU7I+iZMMLU1oQIVVAjNOwygt7c3r0VZllmHmKgAEE7tUagiLFlxrN+pm0D6lLwA4HgTHcKpVMZSVjrUFpD2I31hJRMGvbuYj6fE7bq16qDmI3BAzzm52oY5Dguy9yaR5Z5RFJDYSP71c3foRUbhqcVYmOsxg0mqikM+JhkZejtQegdGyLlTjbYVmwxn7v9h5hoQW5brBhpTZkxeZI4+DnHQNZt5La4D9aQ64lD8NpqJxX470l6EJzEZSMEXytld19TDn0H54d83UL98Ez+PuxjTvAfHgL4HgQ/1nDtt4C5fH3zDfb0PhbpVzpF6BeKPyFY1UWNGfapMw3JnuCS2i/pdqTZ/grXewQTDktFoRE5JrzgdE+fX1j9Se6iWKQ+8pNczLc502t34mMu/EtCM7LYFtGFqizrxlAbXaDsfWEAS+N0eUWw0ncGpYZZY/XVonhfXNBJBJymCwh69tvbHTlLJJPFY3+y2888mAZ8tOV1Y0/apqNPSv+NP5oy/gHIRUlh

Steps to reproduce

  1. Create a select[multiple] element with a thousands of options (e.g. 25K options)
  2. Use v-model on it
  3. Try to select a big chunk of options (> 500)

What is expected?

Quick v-model update

What is actually happening?

A very noticeable hang

vue-select-hangs.mov

System Info

No response

Any additional comments?

I'm not just testing performance, I'm actually using this in production, for reasons I won't get into.
I should mention that managing the state manually (e.g. using @change) is fast.

@LinusBorg
Copy link
Member

To a degree, that's expected.

We need to set the selected prop on each affected <option> when the parent sets the value during the re-render that was triggered by the change event of the select. To do that, we have to loo over all option elements, and for each element, look up the option's value in the list of currently selected values passed through v-model.

This is essentially a controlled input, where the component always controls which options are selected.

Your (totally valid) workaround only uses the @change event, which 1) doesn't cause a re-render and 2) thereby skips the work of re-applying the selected attributes to all those options through this bad loop.

We might have some room for optimization here, but to a degree v-model will always be inherently be slower than an uncontrolled select due to the additional work it does.

@4refael
Copy link
Author

4refael commented Jan 6, 2024

@LinusBorg
Copy link
Member

LinusBorg commented Jan 8, 2024

using a Set would indeed be more performant, but it doesn't cover all use cases, unfortunately.

We currently use a looseEqual() function to compare values, because v-model select does support objects, and also supports inline-defined objects like this:

<option :value="{ size: 'small' }"></option>
<option :value="{ size: 'medium' }"></option>
<option :value="{ size: 'large' }"></option>

an implementation with Set could not support that, as these inline objects only match in shape, but not in identity.

We could, in theory, think about a modifier for some kine of "performance" (v-model.opimized) mode that would then use a Set and leave it to the developer to insure to define values in a way that selected values can be identified through identity comparison.

But then again: Should we optimize for selects with lists so large that they are unusable anyway?

Edit: Looking at our implementation again, there could be away to use a fast path with a Set automatically for primitive values ...

@4refael
Copy link
Author

4refael commented Jan 8, 2024

Appreciate the input @LinusBorg. I actually forgot v-model supports objects as a value.

A different strategy could be using a Set to track the indexes of selected options, rather than their values.
I've tested and seems to work fine, it even simplifies my previous implementation.
Possibly there are more edge-cases to consider, but this could be a move in the right direction.

Not sure about the inline-defined objects though, since I'm not aware of a way to access their value.
I assume v-model can internally access it, so possibly this solution could work in this case as well.

https://play.vuejs.org/#eNqNVMtu2zAQ/JWtLpEBmzLi5qLaadIih/bQFk1vVlCo0tpiQlECSck2DP17l6TkKk4R5GRyZ/Yxw7WOwW1ds7bBIA6WOlO8NqDRNPV1InlZV8rAERRuppBVZd0YzKGDjapKuKCki0QmMqukNlDVhtMBVpYd3iqVHpjlhUcQKLemiOHyaj6fQzeF8PcU+ARW10Bom4oGY+DQTSaToZpGgZlt5sutH14gl2NoAF0tfY+GwGHeMHSdJO6AgHDIZ45rOyZy08jMTg9ZkcothtiiNBM4JhJO/Tyf6q4ZY47ATKq2aFiv/MGyAViZ1mHoY4NKf2MnUR9JbQyyEYLau6QNFwZVyC2bw7vV6hlqSzqob+VnWXMrvUvkMvIPR09GF4NlLVKDdANY+p5w45WtksAfkgDKRhheC88jpq8N/gbQzjaVIn7oejklXA4DJMFAix1MPPc7ij/hgaJ8FBnkD2T7TqxIdW+Wdnp6ej8UwLFfEOhIqJsz8nQvL/JFnXK65ry9vu/bxDb3ZHnXLSOLWrdGDtFVm4MzwVPXgy0P/vl3PLeru5jP6/0HGyiQbwsTA+2yi3j/XY1gGhhNi7jhW/aoK0l/KVeDTKdd5ALV98E+Gs7LSYJUiGr31cWMIqeHeFZg9vSf+KPe21gS/FCoUbVk+gnzG+nhu/tvuKfzCSyrvBHEfgX8iboSjZ3R0z41MqexRzw37Rf3YeBy+0vf7Q1KPYiyg1pm5/j0zg1+fkX6v3EXbOHyyE9y0X94ZrT2Zz564HkR6uGHLYypdRxFWS4pLUfBW8UkmkjWZXRDtEg10vASZ3lV3izYe3ZFK6HNOMxQl7M/qtqRs1RkJNzmO7vVTKHMUVlb3tb2LG3c+gx60f5kSvcXusLjtg==

@github-actions github-actions bot locked and limited conversation to collaborators Feb 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants