JavaScript 数组 vs 对象的性能表现

4
我在这里见证了一些魔法。
首先,这是一个相当常见的问题,相信我,我已经做过研究,所以请在将其标记为重复之前,请听我说完。
数组和对象之间的性能差异已经在这个SO答案中被很好地解释了,我已经将其应用到我的React Native应用程序中,希望它能将我的性能提高约300%。但结果是一个巨大而令人失望的惊喜。
我将数据结构从对象数组改变为...
let poems = [ obj1, obj2, ..., obj64]

将对象的键设置为对象id,值设置为整个对象本身

let poems = { "obj1_id": obj1, "obj2_id": obj2, ...}

现在如果我想访问一个对象,而不是通过循环数组并测试其属性(例如id),我可以直接这样做:poems[obj1_id],这将更为高效(就速度而言)。
无论如何,我都没有看到任何理由不这样做。所以现在我想分享我的源代码(React Native),因为我怀疑问题可能出在我的实现方式上。
以下是我的数据: poems.json:
{
"Family": {
  "1":  {
    "id": "1",
    "category": "Family",
    "favorite": false,
    "body": "Poem 1"
  },
  .
  .
  .
  "64": {
    "id": "64",
    "category": "Family",
    "favorite": false,
    "body": "Poem 64"
  }
}
}

这是我的 reducer: poemReducer.js
  import all_poems from '../data/poems_obj.json';

  const initialPoems = {
      allPoems: all_poems,
      currentPoems: {},
      favoritePoems: {}
  };

  export default poems = (state = initialPoems, action = {}) => {
    switch (action.type) {
      case SET_POEMS:
        return state;
      case SET_CURRENT_POEMS:
        return {
          ...state,
          currentPoems: state.allPoems[action.name]
        };
      case TOGGLE_FAVORITE:
        let currentPoems = state.currentPoems;
        let favoritePoems = state.favoritePoems;

        let poem = currentPoems[action.id];
        poem.favorite = !poem.favorite;

        if (poem.favorite) {
          favoritePoems[poem.id] = poem;
        } else {
          delete favoritePoems[poem.id]
        }
        return { ...state, currentPoems, favoritePoems };
        default: return state;
    }
  }

信不信由你,当我点击收藏按钮来切换诗歌收藏的布尔值时,大约需要 9s 的时间。不是9毫秒,而是9 秒,在只有64个对象大小的对象中。

这是我如何分派动作的:

  export const toggleFavorite = (id) => {
return {
  type: TOGGLE_FAVORITE,
  id
};
}

我做错了什么吗?我对整体想法有什么不理解的地方吗?
非常感谢您提供任何见解。
编辑
如果浪费了任何人的时间,我很抱歉。我意识到我在应用程序的完全不同部分犯了一个错误。在负责渲染诗歌的React Native组件中,我做了以下操作:
首先从redux获取诗歌:
 mapStateToProps = (state) => { poems: state.poems.currentPoems }

由于诗歌在redux中以对象的形式存在,因此这些诗歌的格式如下:

 {
  "1":  {
    "id": "1",
    "category": "Family",
    "favorite": false,
    "body": "Poem 1"
  },
  .
  .
  .
  "64": {
    "id": "64",
    "category": "Family",
    "favorite": false,
    "body": "Poem 64"
  }
}

我正在React Native的FlatList组件中呈现此内容,因此我需要这些数据成为对象数组。所以为了将对象转换为对象数组,在我的render()方法中的return语句之前,我会进行如下操作:

const { poems } = this.props; // grab from redux, via mapStateToProps function
const poemsArr = Object.keys(poems).map(key => peoms[key]); // change into array of objects

然后我将poemsArr作为值传递给我的Flatlist组件的data属性。

  <FlatList
    data={poemsArr}
    renderItem={this.renderItem}
  />

某种方式,这严重拖慢了我的应用程序。

现在我做出的改变是,在render()方法内部将我的对象转换为对象数组的代替方式是直接在mapStateToProps()方法中进行转换:

mapStateToProps = (state) => { poems: Object.keys(currentPoems).map(key => currentPoems[key]) }

这解决了我的问题。目前我还没有一个良好的解释为什么它起作用。这是我现在的任务。

如果这浪费了任何人的时间,我很抱歉。感谢你们的贡献。它们真的帮助了我。

附言:在发布之前,我对原始源代码进行了许多修改,以使其通用和简单。由于我只是初学JavaScript开发者,可能会有一些语法错误。谢谢


1
请更新您的问题,附上一个 [mcve] 来展示问题,最好使用 Stack Snippets 提供一个 可运行 的示例(使用 [<>] 工具栏按钮)。Stack Snippets 支持 React,包括 JSX;这里是如何创建一个 - T.J. Crowder
1
你的调试器和/或分析器告诉了你什么?哪一部分负责这9秒的时间? - Andreas
1
你正在 TOGGLE_FAVORITE 案例中改变状态。 - webmaster
1
不应该直接为找到的对象分配值,这会改变状态。'poem.favorite =!poem.favorite;'或者'favoritePoems [poem.id] = poem;'是错误的。 - webmaster
1
请执行以下操作: const poem = { ...currentPoems[action.id]; favorite: !currentPoems[action.id].favorite } - webmaster
显示剩余4条评论
1个回答

0

您添加了很多代码,所以我无法使用它进行复制,但根据我的理解,您只需迭代输入数组即可实现它。

const poems = [
    {
    id: 1,
    name: 'obj1'
  },
  {
    id: 2,
    name: 'obj2'  
  },
  {
    id: 3,
    name: 'obj3'
  },
  {
    id: 4,
    name: 'obj4'
  }
];

let obj = {};

poems.forEach((item) => {
    obj[item.id] = item;
});

console.log(obj);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接