-
-
Notifications
You must be signed in to change notification settings - Fork 861
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
Destroy of hundreds is slow #926
Comments
In vue-i18n the problem appears right here: beforeDestroy: function beforeDestroy () {
if (!this._i18n) { return }
var self = this;
this.$nextTick(function () {
if (self._subscribing) {
self._i18n.unsubscribeDataChanging(self);
delete self._subscribing;
}
if (self._i18nWatcher) {
self._i18nWatcher();
self._i18n.destroyVM();
delete self._i18nWatcher;
}
if (self._localeWatcher) {
self._localeWatcher();
delete self._localeWatcher;
}
});
} This is called for each component, so it stacks nextTick. Usually, I would assume that those nextTicks will be run async, but they don't, they are stacked in a sync queue and cause serious bottlenecks: I think the reason for this is not having many components, but have deep nesting structures. The beforeDestroy for the parent is only called on the nextTick of the child, maybe. I'm not deep enough into it, so I can only make assumptions. I need a work around, any help is appreciated. |
We experienced the same problem and came to the same conclusion as @martin-braun. We think the problem has nothing to do with the directive (we don't use it) but with every mounted component. Vue i18n tracks every component in the VueI18n root instance (
When some i18n parameter changes (e.g. the locale), the root VueI18n queues an update for all of them. In practice, this process is quite fast: https://github.com/kazupon/vue-i18n/blob/v8.21.0/dist/vue-i18n.esm.js#L1233 By contrast, destroying a component implies removing the component from the
In a nutshell, removing nearly all elements has a cost of I think the i18n reactivity is something desired most of the time but avoidable in many scenarios. For instance, suppose we are displaying a large grid on the screen with 1000 cells. Each cell is composed of 4 components, which means a total of 4000 elements on the |
Reading the code, it looks impossible to deactivate the reactivity for a single component. The mixin is responsible for adding and removing the component to the tracking list, and there is no way to modify its behaviour. We are testing this temporary solution that removes the reactivity once mounted (since it was added on import VueI18n from 'vue-i18n';
import { Component, Vue } from 'nuxt-property-decorator';
@Component({})
export default class FastI18nMixin extends Vue {
_subscribing?: boolean;
_i18n?: VueI18n;
_i18nWatcher?: any; // Vue Watcher (type not exported)
_localeWatcher?: any; // Vue Watcher (type not exported)
mounted() {
if (this._i18nWatcher || this._localeWatcher) {
console.warn('Unexpected i18n attributes. Is this the Vue Root?');
return;
}
/*
* Reproduce the beforeDestroy stuff:
* https://github.com/kazupon/vue-i18n/blob/v8.21.0/src/mixin.js#L117
*/
if (this._subscribing && this._i18n) {
(this._i18n as any).unsubscribeDataChanging(this); // method not typed
delete this._subscribing;
delete this._i18n;
}
}
} We tested this mixin on an infinite scroll page that renders user cards. Each user card is a bit complex, having an avatar, a rating, and a few buttons. After loading nearly 1800 cards, we click on a link that renders a simple page. What we are trying to reduce is the amount of time spent destroying all the stuff related to the user cards. Before modifying the code:
After modifying the code:
We can apply the As expected, despite that the length of the I think it would be worth being able to disable the reactivity for a component and its children. If we can disable children components, we can disable reactivity for external libraries (like Bootstrap Vue). Or it might be better to set a default behaviour and modify it on each component through their options. @exoego what do you think? |
@emarbo
I was wondering if we could reduce a computational cost. 🤔 |
@exoego Thanks for the response! 👏
There's no much to do using a list. There is a single event of interest (the locale update) and a list of listeners (the The only alternative I see is using a Map, where the values are the components and the keys are their Supposing the Map approach makes sense, I don't know which is the right solution. Being able to "not subscribe" some nodes to the locale changes, or keep all nodes subscribed (despite not having translations) but improving someway the underlying data structure. Maybe both changes are of interest? Maybe the Map change is more risky? 🤔 |
@exoego thanks for the quick PR!! 👏👏👏 |
I merged #1175 , and published v8.24.3 |
@exoego, @kazupon,
Thank you very much for the quick fixing. It helped a lot! 👏👏👏 |
Closing as resolved in v8.24.3. |
There seems to be a performance issue, when using the v-t directive. We have components for Input elements in our application and are using v-t translations to display labels for the input elements.
When there are hundreds of components displayed under a main component, then the destroy of the main component is taking very long (speaking of up to 10-15 seconds to destroy.
Our basic structure:
MAIN COMPONENT
vue & vue-i18n version
vue 2.6.11
vue-i18n 8.15.3
Steps to reproduce
Create a component with hundreds (around 600 in our case) of sub components where the subcomponent uses v-t to translate text for the input labels.
What is Expected?
Destroy of main component happening fast (< 2sec - is the result when commenting out the directive)
What is actually happening?
Destroy of main component takes long (> 10 sec)
The text was updated successfully, but these errors were encountered: