高田悠*_*高田悠 6 javascript performance vue.js
1我有一个用vue.js创建的时间表组件,它包括约200个子时间轴组件(以嵌套形式)(我想上传图像,但不能没有10个声誉)。
现在的问题是,销毁该组件需要花费6秒钟以上的时间。
Chrome表示“删除”功能(每次我们销毁组件时都会由vue.js调用)被调用了很多次,每个功能大约需要20到40毫秒。
vue.js的删除功能如下所示:
function remove (arr, item) {
if (arr.length) {
var index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1)
}
}
}
Run Code Online (Sandbox Code Playgroud)
似乎第一个参数arr是几个VueComponents或超过2000个Watcher对象。
现在,我的问题是:1.在这种情况下,“观察者”是什么,为什么它的数量超过2000?2.为什么我不处理大约10000个组件,却要花这么长时间?
我想这是vue.js规范的问题,但是如果您有类似的问题或对此有任何想法,请帮助我。谢谢!
上面是时间线组件的显示方式,灰色背景面板和紫色背景面板(带有男人图标)都是子组件。当您单击紫色面板时,vue-router会路由到详细信息页面,并且那时所有组件都被销毁(也就是说,发生上述问题时)
我们遇到过类似的问题,发现它们都有一个共同的潜在问题:依赖同一个响应式对象的组件太多。以下是可能影响任何项目的 3 种主要情况:
router-link组件我们的方法是避免访问渲染和计算属性函数上的共享反应对象。相反,将它们作为props(反应性)传递或在created或updated钩子(非反应性)上访问它们以存储在组件的$data. 阅读下文了解更多详细信息以及 3 个案例中的每一个。
(不需要的可以跳过)
Vue 反应性基本上依赖于两个相互交织的对象:Watcher和Dep。Watchers在deps属性中有一个依赖列表(Deps),Deps在属性中有一个依赖列表(Watchers)subs。
对于每个响应式事物,Vue 都会实例化一个 Dep 来跟踪对它的读取和写入。
Vue 为每个组件(实际上是render函数)和每个计算属性实例化一个 Watcher 。观察者在执行过程中观察函数。在watch 时,如果读取了一个响应式对象,关联的 Dep 会注意到 Watcher,并且它们变得相关:Watcher.deps包含Dep,和Dep.subs包含Watcher。
之后,如果反应性事物发生变化,则关联Dep 通知其所有依赖项 ( Dep.subs) 并告诉他们更新 ( Watcher.update)。
当一个组件被销毁时,它的所有 Watcher 也会被销毁。这个过程意味着迭代每个Watcher.deps以从Dep.subs(参见Watcher.teardown)中删除 Watcher 本身。
所有依赖于同一个反应性事物的组件都在同一个Dep.subs. 在以下示例中,它Dep.subs包含 10,000 个观察者:
销毁页面时,10,000 个观察者会将自己从Dep.subs数组中移除(一个一个)。除去本身的成本10k * O(10k - i),其中i已被移除观察家的数量。
一般来说,移除n物品的成本是O((n^2)/2)。
如果您渲染许多组件,请避免访问对render或 计算属性的共享反应依赖项。
相反,将它们作为props或访问它们的created或updated钩子并将它们存储在组件的$data. 请记住,钩子不会被监视,因此如果数据源发生变化,组件将不会更新,这仍然适用于许多情况(安装组件后数据不会更改的任何情况)。
如果您的页面呈现一长串项目,vue-virtual-scroller肯定会有所帮助。在这种情况下,您仍然可以访问共享的反应式依赖项,因为 vue-virtual-scroller 重用了一小部分组件(它不会呈现看不见的东西)。
考虑到拥有数千个组件可能比您预期的要容易,因为我们倾向于编写小组件并组合它们(实际上是一种很好的做法)
案例:Vuex
如果你在你的 render o 计算属性中做这样的事情,你的组件依赖于所有反应性事物链:state, account, profile。
function myComputedProperty() {
this.$store.state.account.profile.name;
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,如果你的帐户在组件挂载后没有改变,你可以从createdorbeforeMount钩子中读取它并将其存储name在 Vue 上$data。由于这不是渲染函数的一部分,也不是计算属性的一部分,因此没有观察者监视对存储的访问。
function beforeMount() {
this.$data.userName = this.$store.state.account.profile.name;
}
Run Code Online (Sandbox Code Playgroud)
案例:路由器链接
案例:Vue I18n
这具有相同的潜在问题,但解释略有不同。见问题#926
这不是 vue 问题,请参阅您的 mixins/options。
例如。i18n(我的痛苦)200 个组件中的每一个都会显示相同的结果。它消除了很多关注者beforeDestroy。如果没有i18n列表,工作速度会快 30 倍。
如何修复它?将慢速钩子处理程序移至父组件并从中获取所需的数据/方法。
样品与i18n
Vue.mixin({
beforeCreate() {
if (this.$options.useParentLocalization) {
this._i18n = parent.$i18n;
}
},
});
Run Code Online (Sandbox Code Playgroud)
用法:
new Vue({
// i18n, <-- before
useParentLocalization: true,
components: {
Component1
}
})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
241 次 |
| 最近记录: |