7

Basically the code that broke my node js express server was this:

resultArr = [];
resultArr["test"] = [];
resultArr["test"][2015073012] = someObject;

when I changed this to this, it ran without problems

resultArr = [];
resultArr["test"] = {};
resultArr["test"][2015073012] = someObject;

I did work like this in a loop.

Why did it break my app?

Toskan
  • 13,911
  • 14
  • 95
  • 185
  • 1
    It depends on the specific JS implementation (V8 in this case). I am surprised it caused it to 'crash' as I would expect it to have been built as - or converted to - a sparse-array implementation (being that it is over ~105k indexes). If it does cause it to 'crash' then my first hunch is it is still trying to use the dense-array implementation .. or that something else is amiss. – user2864740 Jul 31 '15 at 05:31
  • Can you show more of your code? What you have there works just fine. – Aaron Dufour Jul 31 '15 at 05:33
  • According to ES5, the maximum length of an array is 2^32-1,but it will be sluggish if the the array have many element, until out of memery. – kenticny Jul 31 '15 at 05:45
  • @kenticny That is not entirely true. Modern JS engines have several different array implementations - most notably: a 'dense' backed by a continuous allocation, and a 'sparse' more like a normal object - and can switch between them; and the behavior and conditions are entirely implementation-dependent. Why V8 is failing to do so in this case is the question.. I would not be surprised if there is a bug report somewhere. – user2864740 Jul 31 '15 at 06:08
  • Related to the *different* backing implementations: http://stackoverflow.com/questions/16961838/working-with-arrays-in-v8-performance-issue , http://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/ – user2864740 Jul 31 '15 at 06:14
  • 1
    @user2864740 - Thanks for the interesting and informative comments, both above and the (now deleted) comments on my answer that kept me on my toes while I was writing it. :-) You made a great contribution to this discussion. – Michael Geary Jul 31 '15 at 06:46

1 Answers1

7

As you found, you shouldn't be using arrays for this, you should be using objects. But you should go a step further and use an object for the top level as well. And since your 2015073012 value will be used as a string, it's a good practice to make it one from the start:

var results = {};
results.test = {};
results.test['2015073012'] = someObject;

or:

var results = {};
results['test'] = {};
results['test']['2015073012'] = someObject;

Now you won't have any problem in any JavaScript engine.

(As an aside, I changed the name from resultArr to results so the name doesn't make it sound like it's an array.)

JavaScript arrays are for cases where you have sequential entries like array[0], array[1], array[2], etc. When you have arbitrary strings or arbitrarily large numbers for keys, do not use an array, use an object.

Don't be confused by other languages such as PHP that have a single array type which serves both as a sequential 0,1,2,3,... array and as a dictionary of key-value pairs. JavaScript has both arrays and objects: use arrays for the sequential case and objects for the key-value case.

Back to your question, why did this code break:

resultArr = [];
resultArr["test"] = [];
resultArr["test"][2015073012] = someObject;

One possible explanation is that the JavaScript engine is doing exactly what you told it to do when you assign a value to the [2015073012] array index: it creates an array with 2,015,073,013 entries (one more than the value you gave, because array indexes start at 0). That is over two billion entries in your array! You can probably see how that would cause a problem - and it certainly isn't what you intended.

Other engines may realize that this is a ridiculously large number and treat it as a string instead of a number, as if you'd used an object instead of an array in the first place. (A JavaScript array is also an object and can have key-value pairs as well as numeric indices.)

In fact, I crossed my fingers and tried this in the JavaScript console in the latest version of Chrome, and it worked with no problem:

a = [];
a[2015073012] = {};

But you weren't as lucky. In any case, you should always use objects instead of arrays for this kind of use, to insure that they are treated as key-value pairs instead of creating enormous arrays with mostly-empty elements.

Michael Geary
  • 28,450
  • 9
  • 65
  • 75