Use SerializeJSON to return an array of structs in

2019-05-24 15:04发布

问题:

I am building a Railo app which deals with a lot of JSON data sent back and forth via Ajax. I've identified an opportunity to optimize its performance, but I'd like to hear some advice from the community before I tackle it.

Here is a good example of the situation.

I have an action on the server that queries a set of bid responses, serializes them to JSON, then returns them to my javascript on the front end, which then parses and renders some HTML. The format in which Railo returns the JSON is the familiar two-node object:

{"COLUMNS":["one","two","three",...],"DATA":["value","value","value",...]}

I wrote a function that utilizes underscore's map() function to convert this format into an array of objects with named nodes:

function toArgsObject(data,columns) {
return _.map(data, function(w){
    var q = {};
    for (var i=0; i < w.length; i++) { eval("q."+columns[i]+" = w[i]"); };
    return q;
});
};

This gets the job done nicely, however the performance isn't very good! Even with swift js interpreters like those in webkit and firefox, this function often accounts for 75% of processing time in the functions that call it, especially when the data sets are large. I'd like to see how much improvement I would get by offloading this processing to the server, but I don't quite have the cfml / cfscript chops to write an efficient version of this.

What I need to come back from the server, then, would look like this:

[
{"one":"value","two":"value","three":"value"},
{"one":"value","two":"value","three":"value"}.
...
]

I understand that the format used by SerializeJSON creates responses that are far smaller and therefore use less bandwidth to send. This is where the experimentation comes in. I'd like to see how it impacts my application to do things differently!

has anyone written a JSON Serializer that can return data in this format?

回答1:

eval should only be used in a few very rare cases and this certainly isn't one of them. Stop using eval and do this instead:

q[columns[i]] = w[i];

In JavaScript, foo['bar'] is the equivalent of foo.bar.



回答2:

If you need an array of structures in JS, you can easily convert the query into this type of dataset on the server-side and apply the SerializeJSON().

Quick example 1

<cfset dataset = [
    {"one":"value","two":"value","three":"value"},
    {"one":"value","two":"value","three":"value"}
] />

<cfoutput><p>#SerializeJSON(dataset)#</p></cfoutput>

(I love the freedom of structure definition syntax in Railo)

Quick example 2

<cfquery datasource="xxx" name="qGetRecords">
    select userId, login, email from users limit 0,3
</cfquery>

<cfset dataset = [] />

<cfloop query="qGetRecords">
    <cfset record = {} />
    <cfset record["one"] = qGetRecords.userId />
    <cfset record["two"] = qGetRecords.login />
    <cfset record["three"] = qGetRecords.email />
    <cfset ArrayAppend(dataset, record) />
</cfloop>

<cfoutput>
    <p>#SerializeJSON(qGetRecords)#</p>
    <p>#SerializeJSON(dataset)#</p>
</cfoutput>

Should work for you.



回答3:

In Coldfusion 10 or Railo 4, you could use the toArray() function of the Underscore.cfc library to convert your query into the format you want before calling serializeJSON(). Example in cfscript:

exampleQuery = queryNew("one,two,three","Varchar,Varchar,Varchar",
[
    ["value","value","value"],
    ["value","value","value"]
]);

arrayOfStructs = _.toArray(exampleQuery);

serializeJSON(arrayOfStructs);

Result:

[{ONE:"value", TWO:"value", THREE:"value"}, {ONE:"value", TWO:"value", THREE:"value"}]

The toArray() function returns an array of structs that matches your query, which is why the resulting JSON is formatted in the way that you want.

[Disclaimer: I wrote Underscore.cfc]