在我的Vue应用程序中,我有Vuex存储模块,这些模块的状态中包含大量的资源对象。为了轻松访问这些数组中的单个资源,我制作了Vuex getter函数,将资源或资源列表映射到各种键(例如'id'或'tags')。这导致性能下降和巨大的内存占用空间。没有太多重复的数据,如何获得相同的功能和反应性?
export default {
state: () => ({
all: [
{ id: 1, tags: ['tag1', 'tag2'] },
...
],
...
}),
...
getters: {
byId: (state) => {
return state.all.reduce((map, item) => {
map[item.id] = item
return map
}, {})
},
byTag: (state) => {
return state.all.reduce((map, item, index) => {
for (let i = 0; i < item.tags.length; i++) {
map[item.tags[i]] = map[item.tags[i]] || []
map[item.tags[i]].push(item)
}
return map
}, {})
},
}
}
export default {
...,
data () {
return {
itemId: 1
}
},
computed: {
item () {
return this.$store.getters['path/to/byId'][this.itemId]
},
relatedItems () {
return this.item && this.item.tags.length
? this.$store.getters['path/to/byTag'][this.item.tags[0]]
: []
}
}
}
答案 0 :(得分:2)
要解决此问题,请参考编程中的一种古老的标准做法:建立索引。您可以将地图存储到state.all
中该项目的索引中,而不是存储具有在getter中重复的完整项目值的地图。然后,您可以创建一个新的getter,该getter返回一个函数来访问单个项目。以我的经验,索引getter函数总是比旧的getter函数运行得更快,并且它们的输出占用的内存空间要少得多(平均我的应用程序要少80%)。
export default {
state: () => ({
all: [
{ id: 1, tags: ['tag1', 'tag2'] },
...
],
...
}),
...
getters: {
indexById: (state) => {
return state.all.reduce((map, item, index) => {
// Store the `index` instead of the `item`
map[item.id] = index
return map
}, {})
},
byId: (state, getters) => (id) => {
return state.all[getters.indexById[id]]
},
indexByTags: (state) => {
return state.all.reduce((map, item, index) => {
for (let i = 0; i < item.tags.length; i++) {
map[item.tags[i]] = map[item.tags[i]] || []
// Again, store the `index` not the `item`
map[item.tags[i]].push(index)
}
return map
}, {})
},
byTag: (state, getters) => (tag) => {
return (getters.indexByTags[tag] || []).map(index => state.all[index])
}
}
}
export default {
...,
data () {
return {
itemId: 1
}
},
computed: {
item () {
return this.$store.getters['path/to/byId'](this.itemId)
},
relatedItems () {
return this.item && this.item.tags.length
? this.$store.getters['path/to/byTag'](this.item.tags[0])
: []
}
}
}
更改似乎很小,但是在性能和内存效率方面却有很大的不同。和以前一样,它仍然是完全被动的,但是您不再需要复制内存中的所有资源对象。在我的实现中,我抽象出了各种索引方法和索引扩展方法,以使代码易于维护。
您可以在github上查看完整的概念证明,网址为https://github.com/aidangarza/vuex-indexed-getters
答案 1 :(得分:1)
虽然仅存储选择字段是一个很好的中间选项(每个@aidangarza),但是当您最终获得大量数据时,它仍然不可行。例如。积极处理200万条“仅2个字段”的记录仍然会消耗您的内存并破坏浏览器的性能。
通常,在Vue中使用VueX处理大型(或不可预测)数据集时,只需完全跳过get和commit机制。继续使用VueX集中化CRUD操作(通过Actions),但不要尝试“缓存”结果,而是让每个组件在使用它们之前一直缓存所需的内容(例如,结果的当前工作页) ,某些投影等等)。
根据我的经验,VueX缓存旨在用于合理限制的数据或当前使用上下文中(即当前登录的用户)的有限数据子集。当您对数据的规模一无所知时,可以仅通过Actions保持Vue组件“根据需要”访问数据;那些潜在的巨大数据集不会发生吸气剂或突变。
答案 2 :(得分:-1)
虽然我同意@aidangarza,但我认为您最大的问题是反应性。特别是computed
属性。这就增加了很多of肿的逻辑和慢速的代码,可以监听所有内容,而您则不需要。
查找相关项目将始终会导致您遍历整个列表-绕不上任何简单的方法。但是,如果您自己调用它,它将更快。
我的意思是,计算属性是关于将要计算的内容。您实际上是在过滤结果。将观察者放在变量上,然后自己调用getter。大致内容(半代码):
watch: {
itemId() {
this.item = this.$store.getters['path/to/byId'][this.itemId]
}
}
您可以先使用item
进行测试,并且是否可以更好地工作(我相信这样做会更好)-为更复杂的标签添加观察者。
祝你好运!