对于redux减速器,哪种速度更快:交换机还是Map?

qeeaahzv  于 2022-11-12  发布在  其他
关注(0)|答案(3)|浏览(148)

redux文档在推荐reducer的最佳实践时,提到了重构switch语句,并将其替换为action到处理程序的字典/Map,因此:

switch(action) {
  case 'action1':
   doAction1(payload);
  case 'action2':
   doActions2(payload);
}

您将看到如下内容:

var handlers = {
  'action1': doAction1,
  'action2': doAction2,
}
handlers[action](payload);

(see(第10页)
我可以看到字典的方法读起来更干净。我想知道这是不是它被首选的唯一原因?或者字典的性能也超过了开关?

5hcedyr0

5hcedyr01#

在任何真实的应用程序中,它对性能都没有任何影响。
也就是说,你也不应该去考虑它,而是使用官方的Redux工具包,这是官方推荐的编写Redux的方法,已经有两年了--在那里你只需要使用createSlice函数,它会接受一个case reducerMap,用immer Package 它们,并为你做很多其他方便的事情。
要快速了解Redux Toolkit,请查看https://redux.js.org/tutorials/fundamentals/part-8-modern-redux
关于“现代Redux”的完整教程,请看https://redux.js.org/tutorials/essentials/part-1-overview-concepts

olhwl3o2

olhwl3o22#

有些人在意识形态上反对switch语句,部分原因是可能会意外地丢失break语句,并产生失败的情况。在redux reducer的情况下,这不是一个问题,因为每个情况都返回新的状态,所以我个人对这里的switch没有任何问题,我甚至不确定我是否同意字典是任何“更干净”的。
WRT性能,我会选择风格上更喜欢的选项,因为在99.9%的redux情况下,您不会频繁地更新状态,这样的小差异就不重要了。但是好吧,让我们来看看哪个执行得更快:

const keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
let count = 0;
const increment = () => ++count; // just do something on each action
console.time("switch");
for (let i = 0; i < 10000000; i++) {
  const k = keys[Math.floor(Math.random() * keys.length)];
  switch (k) {
    case 'a':
      increment();
      break;
    case 'b':
      increment();
      break;
    case 'c':
      increment();
      break;
    case 'd':
      increment();
      break;
    case 'e':
      increment();
      break;
    case 'f':
      increment();
      break;
    case 'g':
      increment();
      break;
    case 'h':
      increment();
      break;
    case 'i':
      increment();
      break;
    case 'j':
      increment();
      break;
    case 'k':
      increment();
      break;
    case 'l':
      increment();
      break;
    case 'm':
      increment();
      break;
    case 'n':
      increment();
      break;
    case 'o':
      increment();
      break;
    case 'p':
      increment();
      break;
    case 'q':
      increment();
      break;
    case 'r':
      increment();
      break;
    case 's':
      increment();
      break;
    case 't':
      increment();
      break;
    case 'u':
      increment();
      break;
    case 'v':
      increment();
      break;
    case 'w':
      increment();
      break;
    case 'x':
      increment();
      break;
    case 'y':
      increment();
      break;
    case 'z':
      increment();
      break;

  }
}
console.timeEnd('switch');
console.time('map');
const map = keys.reduce((a, b) => {
  a[b] = increment;
  return a;
}, {});

for (let i = 0; i < 10000000; i++) {
  const k = keys[Math.floor(Math.random() * keys.length)];
  map[k]();
}
console.timeEnd('map');

// switch: 529.752ms
// map: 737.213ms

所以switch占了上风,虽然不是很大,但优势很大。然而,在实践中你永远不会注意到它,所以从可读性的Angular 来看,选择你更喜欢的那个。

a14dhokn

a14dhokn3#

这是我在2022年看到的在Chrome中运行你的确切代码:

switch: 304.3369140625 ms
map: 187.68896484375 ms

你也把Map的构建包括在你的时间里。在这种情况下,它并不重要,因为你的循环太大了,但它是一个触摸误导。
这取决于你的用例,但是对于大的条件集,Map通常会更快。对于不同的情况,差异会更明显--对一些情况可能很重要,而对另一些情况则没有。在C++中,这也是完全不同的,因为switch语句可以被编译器优化(在某些情况下,它会对你的键进行类似二进制的搜索),所以要小心泛化。
对于较小的switch语句,这种差异几乎可以忽略不计。作为回应,我更关心的是不同子状态部分访问的switch语句的数量。看起来,由于Redux不知道什么动作类型与特定的reducer相关联,它执行给定状态的所有可能的reducer。也就是说,如果有20个reducer,也许只有3个响应于特定的操作类型,但是所有的都被评估了。如果你通过一个Map按照操作类型Map它,它可能是一个单一的Map查找,产生3个相关的reducer。也许在Redux/React中有一个聪明的方法来优化它,但是这不是真正的开关的错,而是结构(以及可能过度使用渐缩管,这可能是特定应用的设计问题)。

相关问题