Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way cleanly use hidden classes in javascript when you dont know what the properties will be?

I have a (GIS) project which displays large amounts of customer data (Thousands of records) to clients. Where nescessary/possible/required, we use server side pagination/filtering/data manipulation but there are cases where it is most efficient to send the data in JSON format to the client and let their browser do the filtering.

The amount of data is large, so we format it to save on bandwidth and parsing time - instead of individual objects, we send a structure that includes the attribute names first and then the values in a single flat array. On the client, we rebuild this into more traditional json objects before other processing occurs. eg:

{attrNames:["foo","bar"],values:[1,2,3,4,...]) -> [{foo:1,bar:2},{foo:3,bar:4},...]

The code for doing this looks a little like this:

function toObjectArray(attrNames, values){
    var ret = [];
    var index = 0;
    var numAttrNames = attrNames.length;
    var numValues = values.length;
    while(index < numValues){
        var obj = {};
        for(var a = 0; a < numAttrNames; a++){
            obj[attrNames[a]] = values[index++];
        }
        ret.push(obj);
    }
    return ret;
}

Given that the attributes may change depending on the customer data, is there a way to do this translation that takes advantage of hidden classes in modern javascript engines like V8? I have done some micro benchmarks similar to our use case ( http://jsfiddle.net/N6CrK/1/ ) where working with json such that hidden classes are used is orders of magnitude faster than building the objects as above. I can get some of this boost using "eval" to create objects, but this feels ugly (This is demonstrated in the js fiddle). Is there a better way? Perhaps using some variant of Object.create, or something like it?

like image 367
tofarr Avatar asked May 21 '14 09:05

tofarr


2 Answers

You mean something like this right?

function toHiddenObjectArray(attrNames, attrValues){

    var numAttrNames = attrNames.length,
        numValues = attrValues.length;

    function Data( values ) {
        for(var v = 0; v < numAttrNames; v++) {
            this[attrNames[v]] = values[v];
        }
    }

    var ret=[];
    for( var i=0; i<numValues ; i+=numAttrNames ) {
        ret.push( new Data( attrValues.slice(i,i+numAttrNames) ) );
    }

    return ret;
}

You can check our the fiddle here: http://jsfiddle.net/B2Bfs/ (With some comparison code). It should use the same "Hidden Class" (i.e. Data). Not sure how much quicker it is though!

But, if you really want to make your code none blocking, why not load the page, then request the data via AJAX, then run all you code when you get a response.

like image 115
Matthew Wilcoxson Avatar answered Sep 29 '22 10:09

Matthew Wilcoxson


I can get some of this boost using "eval" to create objects, but this feels ugly

There's a less ugly way using the Function constructor. Also, further optimisations can be done by immediately assigning the values to the properties, instead of initialising them with null and then again iterating through the attrs array like the adHoc does it. You'd just pass each of the rows you get in the response (array? string? byte-whatever?) as a parameter to the factory.

Also I've moved the creation of the factory function out of the create function, so that only one function will be instantiated (and optimized after enough calls to it).
A decent amount of the time in your test loop is spent on the getTotal, so I've optimised this in a similar manner. Not using getTotalAdHoc in testing the optimised solution drastically reduces the measured time (you can test with getTotalOptimum as well).

var factory = new Function("arr", "return{"+attrs.map(function(n, i){
    return n+":arr["+i+"]";
}).join(",")+"};");
var getSum = new Function("o","return "+attrs.map(function(n, i){
    return "o."+n;
}).join("+")+";");

(updated jsfiddle)

I haven't yet tried moving the complete loop into the generated code, which could avoid a few function calls, but I don't think this is necessary.

like image 22
Bergi Avatar answered Sep 29 '22 11:09

Bergi