gpt4 book ai didi

javascript - 为什么获取成员比调用 hasOwnProperty 更快?

转载 作者:行者123 更新时间:2023-12-02 22:25:44 25 4
gpt4 key购买 nike

我正在编写一个 JS 对象,它需要对字符串:函数对执行真正基本的键值缓存。该类在客户端上运行,并缓存部分编译的模板以呈现部分页面,因此它可能有 20-200 个项目。

在实际编写该类之前,我认为最好先了解一下最快的缓存检索方法是什么。我想到的选项是:

<强>1。基本属性访问:

if (x[k] !== undefined) {
v = x[k];
}

<强>2。 key 检查(自己):

if (x.hasOwnProperty(k)) {
v = x[k];
}

<强>3。 key 检查(一般):

if (k in x) {
v = x[k];
}

我认为 3 是最快的(检查属性是否存在,但不检索它或担心它存在的位置),1 是最慢的(实际上获取属性,即使它不执行任何操作) )。

Putting all of these into jsPerf产生了一些非常奇怪的结果。在 Chrome(和 Chromium)和 IE 中,#1 的速度大约是 IE 的两倍。在 Firefox 中,#3 稍有优势,但三者之间的性能相似。我是否在虚拟机中运行并不重要,并且版本之间没有太大变化。

我无法解释这些结果。可能 #1 注意到数据不会发生任何变化,因此只是在内部检查 key ,但为什么它比 #3 更快?为什么 #3 没有得到相同的优化?

是什么导致了这些结果?我可能会进行一些 JIT 优化,从而导致数据出现偏差?

更重要的是,为什么浏览器之间的差异如此之大,而 FF 中的所有选项都大致相同?

最佳答案

Chrome (V8) 上 x[k] 性能背后的 secret 位于 this chunk of assembly from ic-ia32.cc 。简而言之:V8 维护一个全局缓存,它将一对 (map, name) 映射到指定属性位置的 indexMap 是 V8 中用于隐藏类的内部名称,其他 JS 引擎以不同的方式调用它们(SpiderMonkey 中的形状结构> 在 JavaScriptCore 中)。此缓存仅针对快速模式对象自己的属性进行填充。快速模式是不使用字典来存储属性的对象的表示,而是更像是具有占用固定偏移量的属性的C结构。

正如您所看到的,一旦第一次执行循环时填充了缓存,它将始终在后续重复中命中,这意味着属性查找将始终在生成的代码内处理,并且永远不会进入运行时,因为所有属性基准是查找对象上实际存在的。如果您分析代码,您将看到以下行:

256   31.8%   31.8%  KeyedLoadIC: A keyed load IC from the snapshot

转储 native 代码计数器将显示这一点(实际数量取决于您重复基准测试的迭代次数):

| c:V8.KeyedLoadGenericLookupCache                               |    41999967 |

这说明缓存确实被命中。

现在,V8 实际上并不为 x.hasOwnProperty(k)k in x 使用相同的缓存,事实上它不使用任何缓存并且总是结束向上调用运行时,例如在 hasOwnProperty 案例的配置文件中,您将看到很多 C++ 方法:

339   17.0%   17.0%  _ZN2v88internal8JSObject28LocalLookupRealNamedPropertyEPNS0_4NameEPNS0_12LookupResultE.constprop.635
254 12.7% 12.7% v8::internal::Runtime_HasLocalProperty(int, v8::internal::Object**, v8::internal::Isolate*)
156 7.8% 7.8% v8::internal::JSObject::HasRealNamedProperty(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Name>)
134 6.7% 6.7% v8::internal::Runtime_IsJSProxy(int, v8::internal::Object**, v8::internal::Isolate*)
71 3.6% 3.6% int v8::internal::Search<(v8::internal::SearchMode)1, v8::internal::DescriptorArray>(v8::internal::DescriptorArray*, v8::internal::Name*, int)

这里的主要问题甚至不是这些是 C++ 方法而不是手写汇编(如 KeyedLoadIC stub ),而是这些方法一次又一次地执行相同的查找而不缓存结果。

现在引擎之间的实现可能有很大不同,因此不幸的是我无法完整解释其他引擎上发生的情况,但我的猜测是任何显示更快的x[k] 性能采用类似的缓存(或将 x 表示为字典,这也将允许在生成的代码中进行快速探测),并且任何在案例之间显示相同性能的引擎要么不使用任何缓存,要么采用所有三个操作都使用相同的缓存(这非常有意义)。

如果 V8 在进入 hasOwnPropertyin 运行时之前探测相同的缓存,那么在您的基准测试中,您会看到不同情况之间的性能相当。

关于javascript - 为什么获取成员比调用 hasOwnProperty 更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21763617/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com