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)
}
}
}
第一个参数arr似乎是几个VueComponents或超过2000个Watcher对象。
现在,我的问题是: 1.在这种情况下,“观察者”是什么,为什么数字超过2000? 2.为什么我不处理大约10000个组件,却要花这么长时间?
我想这是vue.js规范的问题,但是如果您有类似的问题或对此有任何想法,请帮助我。谢谢!
上面是时间线组件的显示方式,灰色背景面板和紫色背景面板(带有男人图标)都是子组件。 当您单击一个紫色面板时,vue-router会路由到详细信息页面,这时所有组件都被销毁(也就是说,当上述问题发生时)
答案 0 :(得分:4)
我们遇到过类似的问题,发现它们都有一个共同的潜在问题:依赖同一个响应式对象的组件太多。以下是可能影响任何项目的 3 种主要情况:
router-link
组件我们的方法是避免访问渲染和计算属性函数上的共享反应对象。相反,将它们作为 props
(反应性)传递或在 created
或 updated
挂钩(非反应性)上访问它们以存储在组件的 $data
中。阅读下文了解更多详情以及 3 个案例中的每一个。
(不需要的可以跳过)
Vue 反应性基本上依赖于两个相互交织的对象:Watcher 和 Dep。 Watchers 在 deps
属性中有一个依赖项 (Deps) 列表,而 Deps 在 subs
属性中有一个依赖项 (Watchers) 列表。
对于每个响应式事物,Vue 都会实例化一个 Dep 来跟踪读取和写入。
Vue 为每个组件(实际上是为 render
函数)和每个计算属性实例化一个 Watcher。观察者在执行过程中观察一个函数。在 watching 时,如果读取了响应式对象,关联的 Dep 会注意到 Watcher,并且它们变得相关:Watcher.deps
包含 Dep
,而 Dep.subs
包含 Watcher
。
之后,如果反应性事物发生变化,关联的 Dep
notifies 其所有依赖项 (Dep.subs
) 并告诉它们更新 (Watcher.update
)。
当一个组件被销毁时,它的所有 Watcher 也会被销毁。此过程意味着迭代每个 Watcher.deps
以从 Dep.subs
中删除 Watcher 本身(请参阅 Watcher.teardown)。
所有依赖于同一个反应性事物的组件在同一个 Dep.subs
上插入一个 Watcher。在以下示例中,同一个 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;
}
在这个例子中,如果你的帐户在组件挂载后没有改变,你可以从 created
或 beforeMount
钩子中读取它并将 name
存储在 Vue {{ 1}}。由于这不是渲染函数的一部分,也不是计算属性的一部分,因此没有观察者监视对存储的访问。
$data
案例:路由器链接
案例:Vue I18n
这具有相同的潜在问题,但解释略有不同。请参阅issue #926
答案 1 :(得分:1)
这不是一个严重的问题,请参见您的mixins / options。
例如。每200个组件中的i18n
(我的痛苦)将显示相同的结果。它删除了beforeDestroy
上的许多观察者。如果没有i18n
,列表的运行速度将提高30倍。
如何解决?将慢速挂钩处理程序移至父组件,并从其获取所需的数据/方法。
带有i18n
Vue.mixin({
beforeCreate() {
if (this.$options.useParentLocalization) {
this._i18n = parent.$i18n;
}
},
});
用法:
new Vue({
// i18n, <-- before
useParentLocalization: true,
components: {
Component1
}
})