2

I have built this chrome extension for our internal portal. There is a form in this portal with just one textarea as an input. Users generally post a set of strings in that form. So my extension stores those values on submit locally and displays the history of commands a user has posted in the form in reverse chronological order.

What I currently do is store each command as a value and current timestamp as key into localStorage. If the user posts same data twice, both are stored as 2 different key value pairs. On each load of the page, I retrieve all the keys from localStorage in an array, sort the array in reverse chronological order. Then iterate through the array again to create another array with objects of key value pair. Then I display them in DOM nodes as history of input commands.

Now this is a very inefficient method, a better way would be to store all the key value pairs in a single JSON.stringifyed string. And whenever user posts same input twice, then the previous value of timestamp should be overwritten for the same command. In short, same command should not be stored twice.

There are two ways of doing that. THAT'S WHERE I NEED HELP.

1st method: Make a single object, with keys as the command and values as current timestamp. Say:

var command = $('textarea').val();
var storageTank = JSON.parse(localStorage["MyTank"]);
storageTank[command] = new Date().getTime();
localStorage["MyTank"] = JSON.stringify(storageTank);

So my storageTank looks like

{ 
  "run": 1331916048253, 
  "stop": 1331916049963, 
  "modify":1331916086324,
  "delete": 1331916099874
  //and so on... Remember there can be as much as 1000 to 1500 of such commands,
  //some of them very large
}

Now my data is stored as an unordered dictionary. Whenever (mostly onload) I need to display them in (reverse) chronological order I will have to make an array of objects, each object containing a key (command) and query (timestamp) and sort it. Like this [{"run": 1331916048253},{"stop": 1331916049963},{"modify":1331916086324},{"delete": 1331916099874}]

2nd method: I store the commands in an array of objects containing just one property and simply use push,pop and reverse for the sake of maintaining chronology. Like

var command = $('textarea').val();
var entity = {};
entity[command] = new Date().getTime();
var storageTank = JSON.parse(localStorage["MyTank"]);
storageTank.push(entity);
localStorage["MyTank"] = JSON.stringify(storageTank);

Now my storage Tank looks like this

[
    {"run": 1331916048253},
    {"stop": 1331916049963},
    {"modify":1331916086324},
    {"delete": 1331916099874}
]

Now I don't need to sort them every time I want to display or in other words, on each page load (which occurs very frequently since the form submission redirects on the same page). But if before saving each command, I will need to first iterate through the array to check weather the same command already exists and overwrite if it does, and that will happen on form submission, that means until this matter is sorted out, the form will not submit.

Now which way will be more efficient.

Thanks in advance.

Juzer Ali
  • 4,109
  • 3
  • 35
  • 62

2 Answers2

3

Your data schema requires a data type that is provides both uniqueness and ordering. Other languages provides this automatically for you (ordered hashes, etc) but in Javascript you need to choose between a object that provides the uniqueness or an array that provides the ordering.

You mentioned that your storageTank objects contains many objects, around 1000-1500, So lets see how long it takes to sort that:

For testing, I created this function that generates an object similar to yours, it uses underscore.js.

function build (size) {
    return _.chain(size)
            .range()
            .shuffle()
            .map(function (v) {return {'command': v};})
            .value();
}

console.log(build(10));
> [
    {'command': 4},
    {'command': 0},
    {'command': 2},
    {'command': 8},
    {'command': 5},
    {'command': 1},
    {'command': 3},
    {'command': 9},
    {'command': 6},
    {'command': 7}
]

So, lets see how long it takes to sort this array by the 'command' key:

b = build(10);
console.time('a');
b.sort(function (a, b) {return a.command - b.command});
console.timeEnd('a')

a: 0ms

I repeated this test for many build(size) values, and this is result:

size: 10,       time: 0ms
size: 20,       time: 0ms
size: 40,       time: 0ms
size: 80,       time: 0ms
size: 160,      time: 0ms
size: 160,      time: 0ms
size: 320,      time: 0ms
size: 640,      time: 0ms
size: 1280,     time: 1ms
size: 2560,     time: 1ms
size: 5120,     time: 3ms
size: 10240,    time: 5ms
size: 20480,    time: 10ms
size: 40960,    time: 28ms
size: 81920,    time: 43ms
size: 163840,   time: 228ms
size: 327680,   time: 444ms
size: 655360,   time: 997ms
size: 1310720,  time: 2330ms

So, unless your object contains more than 100K entries, the sort time will remain under 50ms which is unnoticeable for a human. Even if your object contains that much entries, the JSON. stringify will become your bottleneck and not the sorting.

That means: sorting is very fast. Use your 1st method.

Cesar Canassa
  • 18,659
  • 11
  • 66
  • 69
  • What about iterating, how much time does iterating take over sorting? – Juzer Ali Mar 16 '12 at 20:09
  • On the 1000-1500 range that you mentioned you won't see any noticeable difference between iterating and sorting. In the millions range iterating will be much faster. The problem is that by choosing the 'iterating' solution you will have to make sure that the array is always sorted by hand (by pop, push, etc) any bug that you introduce in your code might break your data. The sorting solution is much safer. – Cesar Canassa Mar 16 '12 at 20:52
  • If I go with 1st option, I will have to create a structure like 2nd one anyway for sorting, coz only arrays can be sorted right? And as for breaking up data due to bug, as far as it can show last 10 commands in correct order I am not much bothered. – Juzer Ali Mar 16 '12 at 21:05
  • Thats true, you must push your object into an array in order to do the sorting. – Cesar Canassa Mar 16 '12 at 21:42
1

You have to choose between storing ordered list or key value pairs in javascript, there is no way around it. However the V8 engine does retain the order of your key/value pairs. Though it needs to be verified/confirmed with extensive testing.

SGK
  • 81
  • 1
  • 7