By Johanna Feng


2019-03-14 07:45:11 8 Comments

Why is it slower to search for a value in an object by key than using for in in JavaScript?

Like this code:

const a = { a: { txt: 1 }, b: { txt: 2 }, c: { txt: 3 }, d: { txt: 4 }, e: { txt: 5 }, f: { txt: 6 } };

console.time('1');
let n = a['e'].txt;
console.log(n, '<<n')
console.timeEnd('1');

console.time('2');
for (const key in a) {
    if (a[key].txt == 5) {
        const m = a[key];
        console.log(m, '<<m')
        break;
    }
}
console.timeEnd('2');

The result is

5 '<<by key'
1: 2.329ms
{ txt: 5 } '<<for in '
2: 0.447ms

Isn't this weird?

4 comments

@Arthur 2019-03-15 16:50:11

As you can see here, testing with JS can be really a mess.

const a = { a: { txt: 1 }, b: { txt: 2 }, c: { txt: 3 }, d: { txt: 4 }, e: { txt: 5 }, f: { txt: 6 } };

let test = function(x) {
  console.log("Test "+x+" times")
  console.time('1');
  for(let i=0;i<x;i++) {
     let n = a['e'].txt;
  }

  console.timeEnd('1');
  console.time('2');

  for(let i=0;i<x;i++) {
    for (const key in a) {
        if (a[key].txt == 5) {
            const m = a[key];
            break;
        }
    }
  } 
  console.timeEnd('2');
}

test(1)
test(100)
test(100000)
test(100000)
test(100000)
test(10000000)

@Rahul Raut 2019-03-15 11:25:13

In JavaScript you can add or remove properties to objects dynamically. HashMaps are most memory efficient and fast data structures to access the properties. But dynamic nature of JavaScript makes it more difficult and slower. To fix this problem Nodejs V8 Engine internally uses JavaScript hidden classes and inline caching. Both the topics are quite vast to explain in this answer. So please find the blog link here and following is the awesome explanation of Nodejs v8 engine performance video.

In one iteration you can not determine the performance of two algorithms in almost 99% cases. So I have just modified your code and iterated it for 11 times (which is also not sufficient) for the demo purpose. And you can see drastic change in the output.

for (let i = 0; i <= 10; i++) {
const a = { a: { txt: 1 }, b: { txt: 2 }, c: { txt: 3 }, d: { txt: 4 }, e: { txt: 5 }, f: { txt: 6 } };

console.time('Hash map access');
let n = a['e'].txt;
console.log(n, '<<n')
console.timeEnd('Hash map access');

console.time('For in loop');
for (const key in a) {
    if (a[key].txt == 5) {
        const m = a[key];
        console.log(m, '<<m')
        break;
    }
}
console.timeEnd('For in loop');
}

Following is the out-put.

5 '<<n'
Hash map access: 8.580ms
{ txt: 5 } '<<m'
For in loop: 4.301ms
5 '<<n'
Hash map access: 0.177ms
{ txt: 5 } '<<m'
For in loop: 0.377ms
5 '<<n'
Hash map access: 0.170ms
{ txt: 5 } '<<m'
For in loop: 0.196ms
5 '<<n'
Hash map access: 0.162ms
{ txt: 5 } '<<m'
 For in loop: 0.186ms
 5 '<<n'
 Hash map access: 0.483ms
{ txt: 5 } '<<m'
For in loop: 0.465ms
 5 '<<n'
 Hash map access: 0.435ms
 { txt: 5 } '<<m'
 For in loop: 0.503ms
 5 '<<n'
 Hash map access: 0.500ms
 { txt: 5 } '<<m'
 For in loop: 0.471ms
 5 '<<n'
 Hash map access: 0.528ms
 { txt: 5 } '<<m'
 For in loop: 0.487ms
 5 '<<n'
 Hash map access: 0.492ms
 { txt: 5 } '<<m'
 For in loop: 0.494ms
 5 '<<n'
 Hash map access: 1.033ms
 { txt: 5 } '<<m'
 For in loop: 0.726ms
 5 '<<n'
 Hash map access: 0.484ms
 { txt: 5 } '<<m'
 For in loop: 0.649ms

If you observe the output there is drastic change in hash-map access, first it was 8.580ms in second time it was 0.177ms. You can find that after first time hash-map is almost faster than "for in loop". (Sometimes it's not as my system is under a lot of pressure while runnig the code :) )

Also I reversed the order, I put "For in Loop" first and then object [hashmap] following is the result.

{ txt: 5 } '<<m'
For in loop: 16.390ms
5 '<<n'
Hash map access: 0.220ms
{ txt: 5 } '<<m'
For in loop: 0.266ms
5 '<<n'
Hash map access: 0.186ms
{ txt: 5 } '<<m'
For in loop: 0.277ms
5 '<<n'
Hash map access: 0.367ms
{ txt: 5 } '<<m'
For in loop: 0.328ms
5 '<<n'
Hash map access: 0.249ms
{ txt: 5 } '<<m'
For in loop: 0.947ms
5 '<<n'
Hash map access: 4.013ms
 { txt: 5 } '<<m'
For in loop: 0.799ms
5 '<<n'
Hash map access: 0.532ms
{ txt: 5 } '<<m'
For in loop: 0.565ms
5 '<<n'
Hash map access: 0.479ms
{ txt: 5 } '<<m'
For in loop: 0.644ms
5 '<<n'
Hash map access: 0.609ms
{ txt: 5 } '<<m'
For in loop: 0.624ms
5 '<<n'
Hash map access: 0.472ms
{ txt: 5 } '<<m'
 For in loop: 0.509ms
5 '<<n'
 Hash map access: 0.458ms
 { txt: 5 } '<<m'
 For in loop: 0.568ms
 5 '<<n'
 Hash map access: 0.476ms

We can see first for-in loop has taken 16.39ms while the second only 0.266ms. As mentioned in above answer instantiation takes a lot of time, we can easily validate by seeing these numbers.

Conclusion is while writing the code in JavaScript for Nodejs v8 engine, if we don't add/remove properties on objects it will be more fast and efficient. Also code instantiation takes a lot of time while running the first time.

@MasterCassim 2019-03-14 09:50:45

You have an error in your program

if (a[key].txt = 5)

You are not checking if the txt property is equal to 5. You are setting the property to 5 which means you are finished after the first execution of the loop regardless.

@Johanna Feng 2019-03-14 09:52:32

you are right,I think I miss it when I copy ...

@Seblor 2019-03-14 07:50:31

This is because of how the JIT compiler works.

When you start a JS script with Node, the V8 starts interpreting it, while compiling it into native machine code.

Running it in the Chrome Devtools console, I get this output :

5 "<<n"
0.167724609375ms
{txt: 5} "<<m"
2: 0.262939453125ms

NodeJS output :

5 '<<n'
1: 18.684ms
{ txt: 5 } '<<m'
2: 3.713ms

But when inverting the 2 variations :

const a = { a: { txt: 1 }, b: { txt: 2 }, c: { txt: 3 }, d: { txt: 4 }, e: { txt: 5 }, f: { txt: 6 } };


console.time('2');
for (const key in a) {
    if (a[key].txt = 5) {
        const m = a[key];
        console.log(m, '<<m')
        break;
    }
}

console.timeEnd('2');
console.time('1');
let n = a['e'].txt;
console.log(n, '<<n')
console.timeEnd('1');

Output :

{ txt: 5 } '<<m'
2: 22.017ms
5 '<<n'
1: 0.245ms

As you can see, the version that is executed first takes much more time than the second.

However, if you average it, you can see that executing the key access is much faster than the for in loop.

@floriangosse 2019-03-14 07:51:22

And it's really nice to see if you put both variants in separate files and run them.

@Bergi 2019-03-14 13:08:16

Are you sure this is a problem with JIT? My guess would have been initialisation of the console.

@Seblor 2019-03-14 13:13:15

console already exists, it's native code, it doesn't have to be initialized. The V8 compiles your code Just-In-Time, so it's interpreted before the compiling is done, hence the "slow" start

Related Questions

Sponsored Content

40 Answered Questions

[SOLVED] Sort array of objects by string property value

54 Answered Questions

[SOLVED] How to determine equality for two JavaScript objects?

38 Answered Questions

[SOLVED] Check if a value is an object in JavaScript

20 Answered Questions

20 Answered Questions

[SOLVED] Checking if a key exists in a JavaScript object?

3 Answered Questions

[SOLVED] How do I remove a key from a JavaScript object?

  • 2010-08-11 04:59:03
  • Martin Ongtangco
  • 731422 View
  • 1026 Score
  • 3 Answer
  • Tags:   javascript

4 Answered Questions

[SOLVED] Why is <= slower than < using this code snippet in V8?

  • 2018-12-06 02:59:18
  • Leonardo Physh
  • 13795 View
  • 163 Score
  • 4 Answer
  • Tags:   javascript v8

23 Answered Questions

[SOLVED] How can I add a key/value pair to a JavaScript object?

3 Answered Questions

1 Answered Questions

[SOLVED] Why is bind slower than a closure?

Sponsored Content