4

While running some tests on my site, I ended up with an array that has only 10 String in it, but one with a very high index (600 000 000).

Running indexOf on this array is very slow, making the whole tab freeze for several seconds for each call.

When I tried looking for information about this, most seemed to be saying that modern Javascript implementations use sparse array and that it shouldn't be a problem. I'm using the latest Chrome 62.

The issue is actually reproducible just in the Developer Tools' console. If you try running the following code :

test = [];
test[600000000] = "test";
test.indexOf("test");

You'll see that the console takes several seconds to return the index, indicating that Javascript is looping through every index from 0 to 600000000 rather than skipping directly to the one element. Is this normal behavior?

Dino
  • 139
  • 1
  • 10
  • 2
    Yes, that is how JavaScript works – moon Dec 06 '17 at 00:23
  • This may be a help https://stackoverflow.com/questions/8668174/indexof-method-in-an-object-array – moon Dec 06 '17 at 00:25
  • 1
    The function still needs to investigate every single index. There may be some time in the future when JavaScript runtimes deal with this situation, but they don't at present. – Pointy Dec 06 '17 at 00:26
  • @moon No relation whatsoever. The link is about finding the index of an object. – ibrahim mahrir Dec 06 '17 at 00:27
  • If you are interested in checking the existance only you can use [**`Array#includes`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes). It is optimized for this kind of situations. – ibrahim mahrir Dec 06 '17 at 00:28
  • @ibrahimmahrir I said 'may be a help', not 'duplicate of' – moon Dec 06 '17 at 00:32
  • When JavaScript assigns Array values to an index, all of the unassigned index values become `undefined`. You should notice if you `console.log(test.length)` your Array has a length. JavaScript is looping over the entire Array. Why do you want such indexes anyways? – StackSlave Dec 06 '17 at 00:37
  • @PHPglue Each string has an associated ID, and I do searchs both way, retrieving the string with the ID or the ID with the string. So if I need the string I do test[id] and if I need the ID I do test.indexOf(string). Open to suggestions on cleaner way to do that as it feels wrong for sure. PS. Some strings don't have ID and vice versa. – Dino Dec 06 '17 at 00:58
  • 1
    It seems to me like the ECMAScript spec gives the same algorithm for each, incrementing the loop variable by 1 up to length and accessing each property of the object. Why would includes be faster? When I invoke them on a Proxy they both behave as documented, accessing each property counting by 1. – Josh Lee Dec 06 '17 at 02:05

1 Answers1

6

I'm not sure if this is "normal" behaviour, but an easy replacement would be:

function sparseIndexOf(arr, value) {
    return Object.keys(arr).find(function(k) {
        return arr[k] === value;
    })
}

test = [];
test[600000000] = "test";
sparseIndexOf(test, "test")
dave
  • 62,300
  • 5
  • 72
  • 93
  • 1
    Clever workaround. `Object.keys` will return an array of indexes that actually hold a value (in this case wil return `["600000000"]`), so it won't be expensive. – ibrahim mahrir Dec 06 '17 at 00:34