2

Przemyslaw Jan Beigert

 2 years ago
source link: https://medium.com/@przemyslaw.jan.beigert/improve-destroy-performance-in-vue-47e212abe135
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Introduction

Vue in most of the cases is a fast enough framework. However, the time to destroy nodes can be very long. Of course removing elements from DOM is fast operation but vue needs to remove all watchers from the destruct component and that may take up to several seconds.

Component with nested navigation with 12 groups each has ~20 children. After opening all groups, navigation has ~240 items. After user tries to navigate to another view browser frees for a couple seconds.

Navigation
- Group x12
- Item x20

Investigation

Open chromium dev tools, go to the performance section and set CPU: 4x slower after that browser will behave as on an average user computer.

1*SvhNqph64FWQR0pcyfzuVg.png?q=20
improve-destroy-performance-in-vue-47e212abe135

Then record the destruction of navigation. The result:

1*E37YGNNAyJQNjeFmvI_otA.png?q=20
improve-destroy-performance-in-vue-47e212abe135

Oh my God almost 7 seconds of destroy and 0.65 s of update (before destroy) o.O

1*Bs4HdBwAQ3bNamCRpjKJfg.png?q=20
improve-destroy-performance-in-vue-47e212abe135

In the main $destroy there’s many shorter $destroys and all of them have many removeSub calls. Each of removeSub takes 7–15 ms, not much but in total it’s much time of browser freeze.

Reason

Component Item.vue is bind to 5 high order vuex getters was rendered around 240 times.

Also Item.vue has 8 computed properties and 5 of them use vuex getters. All this operations are not expensive, however create many subscriptions. And these subscriptions have to be cleared.

Solution

Moving all computed props and vuex bindings from Item.vue into Group.vue . Group.vue is rendering many Item.vues so we have to map collection of item like this:

Group.vue doesn’t need these attributes but we want to reduce the amount of things to unsubscribe.

Result

1*iHy336uG0w3rkWDf4dOd-g.png?q=20
improve-destroy-performance-in-vue-47e212abe135

Time of $destroy reduced from ~7s to 0.3s (-96%). Also update before it wad reduced from 0.65s to 0.45 (-30%). Notice that is not a perfect solution: because mapper should move to Navigation.vue add pass Group.vue as prop. However moving calculation of a, b, c, d, e will “only” reduced bindings by 55 (12 * 5 – 5). This performance is not great but not terrible.

Conclusion

In vue loading data from store to component is pretty easy: just ...mapGetters('namespace', ['getter']), but not all components should know about the store. Before React’s hooks was very popular to write container that connect data from Redux by mapStateToProps and mapDispatchToPros with a component. It was a lot of boilerplate and thank goodness we can use now useReducer however it has one advantage: get the developer to think about where to put the connection with store. In my opinion we still must care about it because separation of components into logic and presentation not only to keep code clean but also for performance purposes.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK