使用Javascript通过ID查找元素的最佳性能。数组还是对象?

时间:2021-12-06 12:41:18

Let's say I have these two Object, one array and the other one an associative object.

假设我有这两个Object,一个数组,另一个是关联对象。

var peopleObj = {
    1 : 'Joe',
    3 : 'Sam',
    8 : 'Eve'
};

var peopleArr = [
    { id: 1, name: 'Joe'},
    { id: 3, name: 'Sam'},
    { id: 8, name: 'Eve'}
];

Is there a really big overhead when finding an element (by id) with forEach compared to direct associative key ?

与直接关联键相比,使用forEach查找元素(通过id)是否会产生很大的开销?

peopleObj['3'].name = 'New name';

peopleArr.forEach(function(human) {
    if (human.id == 3) {
        human.name = 'New name';
    }
});

1 个解决方案

#1


3  

You'd have to define "really big," and you'd have to test it with your representative data, but the short answer is yes, it's more overhead to use forEach than direct property access, for a couple of reasons:

您必须定义“非常大”,并且您必须使用您的代表性数据进行测试,但简短的回答是肯定的,使用forEach比直接属性访问需要更多开销,原因如下:

  1. Modern JavaScript engines are pretty smart about objects and can optimize direct property access quite well.

    现代JavaScript引擎对于对象非常聪明,可以很好地优化直接属性访问。

  2. To use forEach, you have to make function calls. Function calls are extremely cheap, but they aren't free.

    要使用forEach,您必须进行函数调用。函数调用非常便宜,但它们不是免费的。

  3. In the course of finding the element in the array, you'll be doing various direct property accesses (human.id), so right there you're doing the same work you'd've done with direct access, but you're doing it over and over again.

    在查找数组中的元素的过程中,您将进行各种直接属性访问(human.id),所以你正在做与直接访问相同的工作,但你是一遍又一遍地做。

Now, not all objects are equal in terms of property access time. In particular, with a modern engine like V8, if you do something to the object that makes the engine throw away its optimizations and fall back on "dictionary mode" (treating the object like a hash table, instead of doing smarter things), property access on that object will be a lot slower than on one where the optimizations remain in place. One such operation is delete, which causes V8 to put the object in "dictionary mode." Example on jsperf (Firefox's engine, SpiderMonkey, bizarrely shows an improvement with the object delete was used on; perhaps it's so fast it's a measurement error, but I ran it several times with consistent results...)

现在,并非所有对象在属性访问时间方面都是相同的。特别是,对于像V8这样的现代引擎,如果你对对象做了一些事情,使得引擎抛弃了它的优化并回到“字典模式”(将对象当作哈希表处理,而不是做更聪明的事情),属性对该对象的访问将比优化仍然存在的对象慢得多。一个这样的操作是删除,这导致V8将对象置于“字典模式”。关于jsperf的例子(Firefox的引擎,SpiderMonkey,奇怪地显示了使用对象删除的改进;也许它是如此之快,这是一个测量错误,但我运行了几次,结果一致......)

So in theory, if you had a small number of entries in your array, and you built up the array in a way that let the engine optimize it as a true array behind-the-scenes, and the object you would have used instead would have been in "dictionary mode," maybe you might find a use case where forEach was faster. It doesn't seem likely, but it's remotely possible.

所以从理论上讲,如果您的数组中有少量条目,并且您以一种让引擎将其优化为幕后真实数组的方式构建数组,那么您将使用的对象将是一直处于“字典模式”,也许你可能会找到一个用例,其中forEach更快。这似乎不太可能,但它是远程可能的。

#1


3  

You'd have to define "really big," and you'd have to test it with your representative data, but the short answer is yes, it's more overhead to use forEach than direct property access, for a couple of reasons:

您必须定义“非常大”,并且您必须使用您的代表性数据进行测试,但简短的回答是肯定的,使用forEach比直接属性访问需要更多开销,原因如下:

  1. Modern JavaScript engines are pretty smart about objects and can optimize direct property access quite well.

    现代JavaScript引擎对于对象非常聪明,可以很好地优化直接属性访问。

  2. To use forEach, you have to make function calls. Function calls are extremely cheap, but they aren't free.

    要使用forEach,您必须进行函数调用。函数调用非常便宜,但它们不是免费的。

  3. In the course of finding the element in the array, you'll be doing various direct property accesses (human.id), so right there you're doing the same work you'd've done with direct access, but you're doing it over and over again.

    在查找数组中的元素的过程中,您将进行各种直接属性访问(human.id),所以你正在做与直接访问相同的工作,但你是一遍又一遍地做。

Now, not all objects are equal in terms of property access time. In particular, with a modern engine like V8, if you do something to the object that makes the engine throw away its optimizations and fall back on "dictionary mode" (treating the object like a hash table, instead of doing smarter things), property access on that object will be a lot slower than on one where the optimizations remain in place. One such operation is delete, which causes V8 to put the object in "dictionary mode." Example on jsperf (Firefox's engine, SpiderMonkey, bizarrely shows an improvement with the object delete was used on; perhaps it's so fast it's a measurement error, but I ran it several times with consistent results...)

现在,并非所有对象在属性访问时间方面都是相同的。特别是,对于像V8这样的现代引擎,如果你对对象做了一些事情,使得引擎抛弃了它的优化并回到“字典模式”(将对象当作哈希表处理,而不是做更聪明的事情),属性对该对象的访问将比优化仍然存在的对象慢得多。一个这样的操作是删除,这导致V8将对象置于“字典模式”。关于jsperf的例子(Firefox的引擎,SpiderMonkey,奇怪地显示了使用对象删除的改进;也许它是如此之快,这是一个测量错误,但我运行了几次,结果一致......)

So in theory, if you had a small number of entries in your array, and you built up the array in a way that let the engine optimize it as a true array behind-the-scenes, and the object you would have used instead would have been in "dictionary mode," maybe you might find a use case where forEach was faster. It doesn't seem likely, but it's remotely possible.

所以从理论上讲,如果您的数组中有少量条目,并且您以一种让引擎将其优化为幕后真实数组的方式构建数组,那么您将使用的对象将是一直处于“字典模式”,也许你可能会找到一个用例,其中forEach更快。这似乎不太可能,但它是远程可能的。