arrays - 如何处理大数据(约50000个对象)的Vue 2内存使用情况

标签 arrays performance memory vue.js vuejs2

我正在尝试为Vue 2上的大量半复杂对象实现一个表 View 。基本上,这个想法是从数据库到JS缓存中收集5万到10万行之间的任何数据,然后对其进行动态分析以构建表-带有实时过滤器的 View (文本搜索)。表中的每一行都是可切换的,这意味着单击该行会将行更改为编辑模式,从而可以对该特定字段/单元格进行类似Excel的编辑。

每个对象约有100-150个字段/属性,但是在表中的任何给定时刻仅显示一定数量的'em'(表列可以实时切换)。对于大型数据集,似乎DB正在推送约10-100mb的JSON数据,在这种情况下,这是可以接受的。从性能上讲,性能不是问题-过滤器的运行速度足够快,并且仅将有限的结果呈现给DOM。

一切都已经起作用了,过滤器已经列出了约100行(相对于过滤器而言)(+“显示100个更多”机制等),但是当我将大约8000个对象加载到数组时,内存达到了内存限制。这似乎保留了2 GB的RAM,在Chrome停止一起运行所有JS代码之后(尽管很奇怪,我没有得到任何警告/错误)。

我对行的内存使用情况进行了基准测试,似乎〜1000行保留了大约300mb的内存。这很可能是Vue反应性观察者保留的。

三个问题:

  • 是否有一种方法可以切换特定数组列表对象的反应性(通过索引等),以使数组本身内的对象是不可观察的/不可改变的,除非专门调用使其变得可变(即,当用户单击行时,这样才能进行编辑) -模式)?
  • 您会如何处理Vue的大型数据集,因为反应性似乎会限制内存使用量?请不要建议“将结果限制在后端之内”,因为这不是我在这里寻求的解决方案(即使我可能需要创建两部分过滤,一个用于获取较小的初始数据集,另一个用于实时过滤)。基本上,我试图通过重新考虑Vue的数据体系结构,将“内存末尾”的界限从8 000-> 80 000。将数据集存储在Vue的数据变量中是唯一的问题吗?
  • 我的一个想法是使用Object.freeze或类似的方法将“项目”-数据集设置为不可观察/不可反应,并具有表来呈现两个数据集:一个用于非反应性数据集,另一个用于当前的数据集在edit-mode(单击行时将被推送到“editableItems”数据集)...此处的任何建议(更简单的方法,以便我能够处理一个数组中的所有内容?)

  • 我已经在Angular 1上进行了类似的应用程序,它可以很好地处理5万行,因此我确信它也应该在Vue 2内可行...应该只是找到一种处理反应性的方法。

    最佳答案

    编辑12.03.2019-此答案结尾的其他提示

    自问了这个问题已经有一段时间了,我终于对项目的这一部分进行了优化。对于那些具有这些性能和/或内存问题的人,我想给出一些指导。

    Vue文档从未真正解释过它,但是正如Andrey指出的那样,您可以将组件对象用作自定义对象和对象列表的数据存储。毕竟,这只是一个普通的javascript对象。

    优化之后,我的列表组件设置看起来像这样:

    module.exports = {
        items: [],
        mixins: [sharedUtils],
        data: function() {
            return {
                columns: {
                    all: []
        etc... Lot's of data & methods
    

    items-array充满了成千上万个复杂对象(大约80mb的数据,压缩后的6mb),我将其视为非反应性的。事实证明,这比我想象的要少-与直接对项目使用v-for相比,我已经在使用一种结构,在该结构中,当用户单击某些过滤器按钮和/或输入字符串时,我会触发该数组的过滤。过滤(例如名称)。基本上,此“processFilters”方法通过无响应的项目​​数组并返回已过滤的项目,该项目存储在数据上下文中。因此,它在突变时会自动变得反应灵敏。
    <tr v-for="item in filteredItems" 
    

    这样,filteredItems中的所有项目都保持反应性,但在滤除它们时也会失去反应性,从而节省了大量的内存。将1200mb缩小到400mb,这正是我想要的。聪明!

    几乎没有需要解决的问题。由于项目不在数据上下文中,因此您不能直接在模板中使用它。这意味着不用写...
    <div v-if="items.length > 0 && everythingElseIsReady">
    

    ...我必须存储项目数组的长度以分开数据 Prop 。也可以使用计算值来解决此问题,但我想保留这些属性。

    放弃主要数据数组的反应性并不是一件坏事-最重要的部分是要了解直接针对该基本数组中的项目进行的修改永远不会触发UI和/或任何更改子组件(douh)。只要您以这样的方式分离代码,即您拥有“隐藏的数据容器”(其中包含来自后端的所有结果),并且具有较大的容器(经过过滤的)表示数组,那么这应该不是问题。通过使用良好的REST架构,只要您记得检查将项目保存在非反应性数据存储中后是否也已更新到最新版本,那么使用非反应性数据存储就应该很好。

    另外,我对性能影响不大感到困惑,因为在数百行中有多少个微组件。渲染显然受到了打击,但是即使我要传递大型 Prop 数千次(因为我有成千上万个输入单元的实例),它似乎也没有击中内存。这种对象之一是我的全局翻译键/值对对象,它具有超过2万行已翻译的字符串...但是仍然没有关系。这是有道理的,因为Javascript使用对象引用,并且Vue Core似乎已正确编码,因此,只要您使用诸如props之类的配置对象,您就可以简单地将成千上万个对象引用到同一数据集。

    最后,我想说的是开始对复杂的CRUD对象发疯,而不必担心达到内存限制!

    非常感谢Andrey Popov向正确的方向轻推!

    提示(12.03.2019)

    由于已经有一段时间了,并且随着我继续使用大型和复杂数据集构建UI,我决定放弃一些简短的想法和技巧。
  • 考虑如何管理主记录(即人或产品)与相关记录(子对象/关系对象)。尝试限制为子组件注入(inject)的数据量,因为对于不同的主记录,您可能多次表示同一子对象。问题是这些对象实际上可能不是引用对象!

  • 考虑一下您拥有包含城市对象的人对象的情况。多个人居住在同一个城市,但是当您从后端获取JSON数据时,您确定这些重复的城市对象实际上是一个和同一城市(人与人之间共享/引用的城市对象),还是相似对象的多个表示形式(包含数据完全相同,但实际上每个数据都是一个单独的实例/唯一对象)。假设您有5万个人,每个人都包含相同的子对象/属性“城市”:{id:4,名称:“Megatown”},您是否仅获取了5万个单独的城市实例,而不是一个?是person1.city === person2.city,还是它们看起来相同并且仍然是两个不同的对象?

    如果不确定要引用共享的城市对象还是使用数十个类似子对象的实例,则可以在此简单地在人员列表组件内部进行引用。您的人包含city-id,因此请使用单独的REST方法(getCities)获取城市列表,并在UI级别进行配对。这样,您只有一个城市列表,并且可以从该列表中解析城市并将其注入(inject)到人中,从而仅引用一个城市。或者,您可以从列表中解析城市并将其作为属性传递给您的人员组成部分。

    还请确保考虑子对象的目的。您需要它是反应性的还是静态的?为了节省大量内存,您只需告诉“person.city = city”,它将为每个人事组件注入(inject),但是如果需要响应,则需要使用Vue.set -method。请记住,如果每个城市都需要是自己的实例(以便每个人都具有相似的城市对象,但每个人的属性都必须是可编辑的),则需要确保您没有使用引用的对象!因此,您最有可能需要克隆城市对象,这将消耗浏览器的内存。
  • 您的微组件可能同时包含只读状态和编辑状态的单独 View 状态。这很普遍。尽管如此,实际上您实际上每次都在创建该微组件的实例,因此数千次初始化了该组件。

  • 考虑一下您拥有带有表格和表格行的类似Excel的电子表格的情况。每个单元格都包含您的自定义“my-input”-组件,该组件从布局中获取“readonly”-属性。如果用户界面处于只读状态,则您仅在my-input-component内部显示标签部分,否则,您将显示具有某些特殊条件(例如,日期时间,数字,文本, textarea,select-tag等)。现在,假设您有100行20列,那么您实际上是在初始化2000 my-input-components。现在的问题是-有什么可以改进的(在性能方面)?

    好吧,您可以将my-input-component的readonly-label分离到列表 View ,以便显示readonly-version(标签),或者显示可编辑的my-input-component。这样,您就具有v-if条件,该条件确保除非您特别请求初始化'em(由于行或整个布局从只读->可编辑-状态移动),否则不会初始化这2000个微组件。您可能会猜想,当Vue不需要创建2000个组件时,对浏览器的内存影响将是多么大。

    如果您面临的页面加载速度真的很慢,则可能根本不是VUE。查看渲染到HTML的HTML标签数量。当您有大量标签时,HTML的效果会很差。证明这一点的最简单方法之一是,将具有2000个选项的select-tag重复100次,或者具有一个20000个option-tag。通过具有大量带有不必要的包装div等的微组件,您可能会溢出html标签的数量。同样,深度和标签越少,浏览器和CPU所需的渲染性能就越低。

    尝试通过示例学习良好的HTML标签架构。例如,您可以研究Trello -services仪表板 View 的编程方式。它是相当复杂的服务的非常简单漂亮的表示形式,具有最少的细分。

    有很多方法可以改善内存处理,但是我要说的是,最重要的方法涉及将“隐藏”对象与可见对象分离,如我最初的回答所述。第二部分是了解实例对象与引用对象之间的差异。第三是限制对象之间不必要的数据传递量。

    我个人还没有尝试过,但是有一个Vue虚拟卷轴组件可以通过看似无限量的数据包装来处理任何数量的数据。查看@ https://github.com/Akryum/vue-virtual-scroller这个概念,让我知道它是否为您解决了问题。

    我希望这些指南能为您优化组件提供一些思路。永不放弃希望,总有改进的空间!

    关于arrays - 如何处理大数据(约50000个对象)的Vue 2内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48515997/

    相关文章:

    mysql - 将 perl 数组返回给 MATLAB

    c - 代码行澄清

    ios - Xcode - 我的应用程序崩溃,错误是 "Invalid pointer dequeued from free list *** set a breakpoint in malloc_error_break to debug"

    php - 尝试将 for i+ 放入 mysql 查询、php wordpress 中

    javascript - 我如何按 ABC 对名称的 javascript.map 数组进行排序

    c++ - 为什么两个连续的收集指令比等效的基本操作执行得更差?

    随着多行文本框中字符串的增长,C# 应用程序变得缓慢且无响应

    java - 如何实现 JOptionpane 列表选项?

    c++ - 为什么我的 setter 方法会产生错误的访问错误

    python - 如何操作以下 numpy.where 数组