Javascript 为什么从地图获取比从对象获取慢?

Javascript 为什么从地图获取比从对象获取慢?,javascript,v8,Javascript,V8,我正在考虑将我的状态管理层迁移到使用而不是使用标准对象 据我所知,Map实际上是一个散列表,而对象在后台使用。通常建议,在可能动态添加或删除属性的地方,使用Map更有效 我设置了一个小测试,出乎意料的是,在对象版本中访问值的速度更快 这个。也许我在test1中的代码示例如此之快的原因是因为它使用了fast属性?这似乎不太可能,因为对象有100000个关键点。如何判断对象是否使用快速属性或字典查找?为什么地图版本会更慢 是的,在实践中,看起来像是一个过早的优化,是万恶之源。。。然而,我对其内部

我正在考虑将我的状态管理层迁移到使用而不是使用标准对象

据我所知,
Map
实际上是一个散列表,而对象在后台使用。通常建议,在可能动态添加或删除属性的地方,使用
Map
更有效

我设置了一个小测试,出乎意料的是,在
对象
版本中访问值的速度更快

这个。也许我在test1中的代码示例如此之快的原因是因为它使用了fast属性?这似乎不太可能,因为对象有100000个关键点。如何判断对象是否使用快速属性或字典查找?为什么地图版本会更慢

是的,在实践中,看起来像是一个过早的优化,是万恶之源。。。然而,我对其内部结构很感兴趣,很想知道选择映射而不是对象的最佳实践。

(这里是V8开发者。)

当心微基准点,它们往往具有误导性

V8的对象系统是按原样实现的,因为在许多情况下,它的速度非常快——正如您在这里看到的

我们建议将
Map
用于类似Map的用例的主要原因是,当机器的某些部分“过载”时,对象系统会表现出非局部性能影响。在一个像您创建的小测试中,您不会看到这种效果,因为没有其他事情发生。在一个大型应用程序中(在许多不同的使用模式中使用许多具有许多属性的对象),仍然不能保证这一点(因为这取决于应用程序的其余部分在做什么)但是,如果整个系统以前碰巧遇到这样一种不幸的情况,那么在适当的情况下使用映射很有可能会提高总体性能

另一个原因是映射比对象更好地处理条目的删除,因为这是它们的实现明确预期的常见用例

也就是说,正如您已经注意到的,在抽象中担心这些细节是一种过早优化的情况。如果您有性能问题,请分析您的应用程序,找出花费的时间最多的地方,然后集中精力改进这些方面。如果您最终怀疑使用对象作为贴图会导致问题,那么我建议更改应用程序本身的实现,并测量(使用真正的应用程序!)是否会产生影响


(请参见此处,了解一个相关的、同样具有误导性的微基准,即使是微基准本身,在经过微小修改后也开始产生相反的结果:。这就是为什么我们建议使用真正的应用程序进行基准测试,而不是简单的微型场景。)

V8为简单对象属性采用了许多非常复杂的优化,因为在当今网络上的大多数JavaScript中,这是工作量的很大一部分。此外,除非您真的需要地图键的任意数据类型,否则我不知道迁移到地图的意义何在。此外,在哪里“建议”使用地图更有效?另一个问题是,您运行的代码中,当使用数十万个键从对象/映射检索数据时,54.42 ops/秒的差异是有形的,并且是非常值得关注的?我会担心任何一个开发人员来找我,对一个有100000个键的对象进行代码审查,但那就是我。我认为这是一个过早优化的例子。在我当前的应用程序中,我确实有100000个密钥。它包括一个消息应用程序,其中所有消息都存储在设备上,这似乎是一个合理的用例。是的,你是对的,这不是我目前的瓶颈。我没有遇到性能问题,希望切换到Map可以解决我所有的问题。你会说本文中的基准是不现实的吗?视情况而定。看起来所有这些基准测试都使用了斐波那契函数,这特别意味着所有缓存键都是小整数(
15
或更小,AFAIC)。因此,如果缓存只将整数1到15视为键,那么这些基准非常现实。如果你有其他类型的缓存键,或者数量更大,或者有时删除它们,那么基于小整数的基准显然不具有代表性。是的,我的意思是关于你提到的其他两点。具体来说,该测试不会代表对象的非本地性能影响,也不会代表删除键。参考基准测试代码否,它与堆大小无关。您可能遇到的一个问题是在“megamorphic”缓存系统中抛出太多(几千)个{hidden class,property name}组合。另一个问题是,有许多隐藏的类更改破坏了优化代码的好处(或者,正因为如此,最终禁用了优化)。重现这些情景并非易事,我也故意含糊其辞,因为随着时间的推移,细节会发生变化;关键是,应用程序有时确实会遇到这些问题,而使用
Map
s进行映射可以大大避免这种情况。