1
\$\begingroup\$

I am trying to create a new object with nested value pairs. My initial challenge is that I have a huge object containing lots of junk data, and I'd like to strip away the value pairs that I do not need as well as renaming certain values. Performance is vital as this will iterate over thousands of items. I assume that creating a new object gives better performance than deleting and replacing values within the original object.

I've also put the following code in this JSFiddle: http://jsfiddle.net/mk3cH/2/

var data = [{
  "ID": 20,
  "Title": "Test item",
  "Category": "1;#Local",
  "ContentType": "Item",
  "FileLeafRef": "20;#20_.000",
  "FileRef": "20;#km/Lists/Meny/20_.000",
  "_ModerationStatus": "0",
  "_Level": "1",
  "UniqueId": "20;#{447FEC10-E7E2-4561-A7B3-0433C8C90D31}",
  "FSObjType": "20;#0",
  "PermMask": "0x400001f07fff1bff",
  "Modified": "2013-01-10 11:56:05",
  "owshiddenversion": "8",
  "Created": "2012-04-12 11:53:07"
}, {
  "ID": 27,
  "Title": "Test item 2",
  "ContentType": "Item",
  "FileLeafRef": "27;#27_.000",
  "FileRef": "27;#km/Lists/Meny/27_.000",
  "_ModerationStatus": "0",
  "_Level": "1",
  "UniqueId": "27;#{F7965302-AB39-45AE-9D9E-99BCF39F03B9}",
  "FSObjType": "27;#0",
  "PermMask": "0x400001f07fff1bff",
  "Modified": "2013-04-14 14:00:30",
  "owshiddenversion": "18",
  "Created": "2012-04-20 14:39:02"
}]
var new_object = {}
var keysToIgnore = ['FileLeafRef', 'UniqueId', 'PermMask', 'owshiddenversion', 'Created', '_Level', '_ModerationStatus'].reduce(function (res, key) {
  res[key] = true;
  return res;
}, {});
var object_initiated = false
document.writeln("<b>Desired content of object: </b><br/>");
for (var i in data) {
  for (var key in data[i]) {
    if (key in keysToIgnore) continue;
    if (key == "ID") {
      new_object[i] = {
        "ID": keydata
      }
    } else {
      var keyname = key;
      var keydata = data[i][key]
      document.writeln(keyname + ": " + keydata + "<br/>");
      new_object[i][keyname] = keydata
    }
  }
}
document.writeln("<br/><b>Actual new object content</b><br/>");
document.writeln(JSON.stringify(new_object));
\$\endgroup\$
  • \$\begingroup\$ What is the source of your data? \$\endgroup\$ – 200_success Oct 19 '13 at 0:15
  • \$\begingroup\$ If the first key encountered is "ID", what do you expect should happen? \$\endgroup\$ – 200_success Oct 19 '13 at 0:16
  • \$\begingroup\$ Your demo has an error. \$\endgroup\$ – Joseph Oct 19 '13 at 1:28
  • \$\begingroup\$ @JosephtheDreamer - I forgot to remove the <script> tags when pasting the code snippet into JSFiddle - fixed now. \$\endgroup\$ – Skarven Oct 19 '13 at 5:10
  • \$\begingroup\$ @200_success: The data source is a typical SharePoint list/ Document Library, usually containing from 200 to 700 items, but the amount of items will grow in course of years to come. \$\endgroup\$ – Skarven Oct 19 '13 at 5:12
2
\$\begingroup\$

New Object != Better Performance

First of all, your notion of "new object is faster" isn't "right" all the time. This might be trivial for smaller objects, but for thousands of records and possibly nested objects, this isn't right.

Though you do create lesser code by reconstructing a new object, but not done right, you might end up eating more memory.

  • If you don't dereference the other object properly, it may sit there and just eat up memory. This will give you the "It's dead" page in Chrome.

  • If you do successfully dereference it, due to the size of the object (like you said, thousands), the GC will take time clearing it from memory, seconds at a time. In this event, there will be noticable "choking" of the browser, and stuttering or worse, freezing of animations. Been there, not good user experience.

Use the almighty server

If you are getting this data from the server, it's better that the server handle this operation. Servers are usually faster than the browser, use it to your advantage. That way, you do less on the browser, and prioritize more important tasks, like giving the user a good UI and fast interaction.

Doing it all client side

Now if you can't do it somewhere else but the server, there are ways to speed it up, or at least not freeze the server.

Web Workers

A modern way of doing it is handing it over to another "thread" by making Web Workers do it.

Keep them small

Keeping your loops small. I usually notice a significant lag when iterations go more than 500 (it's not a magical number, just an observation). Keep your loops small, and avoid that long freeze.

Chunk it up

In addition to keeping the data small, if you have more data to churn than just the 500, consider using timers. Timers with 1ms intervals don't really execute 1ms later. They execute at least 1ms later, and when JS is not busy. You can use that to your advantage and schedule short tasks at intervals without breaking the UI. Of course, the operation becomes asynchronous, so you might want to build a crude callback system for this.

var intervalChurn = setInterval(function(){...loop 100 at a time...},0);

Keep the data flat

Nesting introduces more complexity to the data. Say you have an array of 10 objects. If you loop through that array, it's just 10 iterations. But what if that 10 items have 5 nested properties that you also want to loop through. So thats 5 nested properties times 10 items, giving you 50. Nesting more will introduce more iterations.

Use a library

Some of the bright minds in the development world might have already developed functionality similar to what you are Trying to do. Don't reinvent the wheel. In fact, you are doing something similar to Underscore's omit().

\$\endgroup\$
  • \$\begingroup\$ That's a very interesting and helpful reply, you made me reconsider the strategy of creating a new object versus modifying the existing object. Server side - I would do the whole process serverside if possible, but there are limitations to the JSON-producing REST API that force me to first get the data as XML, then convert it to an javascript object so I can use it with jQuery DataTables plugin. Web Workers seem interesting, although IE 9 support is vital for this process, so that'll have to wait. \$\endgroup\$ – Skarven Oct 20 '13 at 17:46
0
\$\begingroup\$

I don't know, but maybe if you got key names that reference object ID then it would be easier to remove an object for example:

<div id = "NoIdea" class="objectContainer">
    <ul>
        <li id="Name">Bla bla bla</li>
        <li id="Age">Bla bla bla</li>
        <li id="Nonsense">Bla bla bla</li>
    </ul>
    <input type="button" class="deleteObject" value="delete" id ="NoIdea" />
</div>

$('.deleteObject').click(function(){
    var objID = $('.deleteObject').attr("id");
    delete Obj[objID];
});
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.