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

Relatively poor performance when prepending to a large array #5086

Closed
CamilleDrapier opened this issue Dec 10, 2021 · 5 comments
Closed

Relatively poor performance when prepending to a large array #5086

CamilleDrapier opened this issue Dec 10, 2021 · 5 comments

Comments

@CamilleDrapier
Copy link

Version

3.2.24

Reproduction link

codesandbox.io

Steps to reproduce

  • Click on the "add 50" button

What is expected?

The action should be reflected immediately

What is actually happening?

The action's result is delayed, and we can observe "Jank - event processing delay" when capturing the performance with Firefox


A similar problem can be observed with splice if the insertion point is close to the beginning of the array. But if we replace unshift with push, there does not seem to be any performance penalty; this seems to point towards something that is run for every existing element in the array.

This problem was not existing in the latest vue2, cf: https://codesandbox.io/s/mystifying-monad-8n0h4?file=/src/App.vue

Might be related to: #4318

@CamilleDrapier
Copy link
Author

If that helps, here is a performance capture of the action described above:

Screenshot_20211210_165732

@posva
Copy link
Member

posva commented Dec 10, 2021

Let's keep one issue with #4318

In your case, you can use a few tricks like Object.freeze() or markRaw() to improve performance. There are a few other tricks in the docs too

@posva posva closed this as completed Dec 10, 2021
@LinusBorg
Copy link
Member

Just as a preliminary explanation:

  • calling push() on an array with 2000 items results in 1 set operation.
  • calling unshift() on an array with 2000 items results in 2001 set operations, as all array items have to be reassigned to index+1.

The latter is still very fast with plain arrays as the Browser JS engine likely has a highly optimized codepath for this. But when a reactivity proxy is involved, that optimization is lost.

@lidlanca
Copy link
Contributor

note that calling unshift in a loop, invokes reactivity overhead per each call.
the lost of optimization mentioned is actually the overhead of the reactivity system implementation.

Adding 50 items to a 2000 items array will iterate the full list 50 times performing different check to maintain the reactivity system ( ~2000 x 50 )

a possible user land optimization is for you to batch the data to a single prepend call.

SFC playground- slow prepend on large list , get faster with batching (10x faster)

can vue batch all prepend mutation calls within the "tick" and invoke logic as if it was an atomic operation, that I do not know.

@yyx990803
Copy link
Member

If you do not intend to mutate the items in the list (e.g. they are server-fetched data), another way to improve performance with large lists is going immutable - mark the list with markRaw to prevent Vue from making it reactive, and trigger list updates by re-assigning the list: example

@github-actions github-actions bot locked and limited conversation to collaborators Oct 6, 2023
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

5 participants