Exploring dojo/json

By on September 21, 2012 4:52 pm

Dojo has long had great support for JSON through dojo.fromJson() and dojo.toJson(). But with the advent of ECMAScript 5’s JSON object, and the increased adoption of this API among browsers, there is now a standard API for JSON parsing and serialization. Dojo 1.7 added a module that aligns with this standard API. This enables Dojo to directly pass through parsing and serialization when native support exists. Using the native JSON parser and serialization is much faster, and allows Dojo to leverage the high-speed, in language capabilities. Also, Dojo’s dojo/json module is based on the feature detection (has() API) system that is integrated with the build system, so it will be possible to leverage the build system to create browser-specific builds (like mobile builds) where this module consumes just a few bytes.

Using dojo/json

To reference the dojo/json module, we include it as a dependency just like any other module:

define(["dojo/json"], function(JSON){
	// JSON variable now available for serialization and parsing
});

To parse a JSON string, we can simply call the parse() method:

define(["dojo/json"], function(JSON){
	var someJsonString = getData();
	// parse the JSON string
	var myData = JSON.parse(someJsonString);
});

The parse() method on dojo/json differs slightly from dojo.fromJson(). Both of these methods can parse any valid JSON. However, the parse() method will delegate to the native JSON parser, which means you must pass truly valid JSON to ensure proper operation. On the other hand, dojo.fromJson() has long used eval() to parse, and therefore has always accepted and parsed any valid JavaScript expression. In order to maintain backwards compatibility, dojo.fromJson() will continue to accept any JavaScript expression, whereas the parse() method on dojo/json will be restricted to valid JSON.

Enforcing Secure Strict Parsing

If a native JSON parser is not available, by default dojo/json will delegate to eval() to parse the JSON. The eval() based parsing is still generally quite fast, but if you are using JSON from an untrusted source, you should use the strict mode parsing. You can select strict mode parsing by setting the second argument to the parse() method to true. For example:

var someJsonString = getData();
// parse the JSON string
var myData = JSON.parse(someJsonString, true);

Strict mode parsing is slower when no native JSON parsing is available (because it has to do extra parsing checks). The second parameter is ignored when a native JSON parser is available since parsing is always strict (and always fast). As the chart below illustrates, when no native parsing is available strict mode is about 2-3 times slower than non-strict mode. Native parsing is significantly faster and dojo/json will always use native parsing when available (regardless of strict mode argument). The dojo.fromJson() function never uses native parsing, so it is 3-4 times slower than dojo/json‘s parse method on browsers with native parsing.

In general it is better to employ security measures on the server-side than the client-side, so if you are retrieving data from your own server, it is recommended that you use a safe, valid JSON serializer on the server rather than relying on strict mode checking on the client side. The parse() function’s strict mode should normally only be used for data coming from an untrusted server.

Serializing JSON

The dojo/json module can also be used for serializing JSON. Once again, this is based on the native JSON API, and will delegate to the native JSON serializer when available. Serialization is very simple, simply pass a JavaScript object, array, or primitive value to the module’s stringify() method:

define(["dojo/json"], function(JSON){
	var object = {foo:"bar"};
	// serialize the JSON string
	var serialized = JSON.stringify(object); // returns '{"foo":"bar"}'
});

The stringify() method also supports a replacer function that can be used to serialize custom data types. For example if we wanted to serialize dates as UTC epoch milliseconds. We can also use spacers to serialize the data with indentation for easy reading. To enable this easy to read format, we give a spacer as the third parameter:

var object = {nested:{props:true}};
// serialize the JSON string
var serialized = JSON.stringify(object, null, "  "); // returns indented objects

The stringify() function is very similar to the legacy dojo.toJson() function. There are a few minor differences:

  • The dojo.fromJson() function will look for a json() or __json__() method on each object for custom serializer. The stringify() method will look for the toJSON() method instead.
  • The dojo.fromJson() function does not accept a replacer function. The second argument is simply a boolean that indicates if pretty printing (indenting) should be used). If pretty printing is chosen (true), the dojo.toJsonIndentStr holds the value of the indentation string.

dojo/json in Baseless Dojo

Dojo 1.7 and 1.8 are designed for building applications without the full Dojo base. While Dojo base is less than 40KB gzipped, some applications (particularly mobile) may wish to create applications with extremely lightweight footprints. The dojo/json module is one of many modules in Dojo that no longer require Dojo base. This module can be used with just a module loader, and no other dependencies. This makes ultra-light applications much more feasible. See our dgrid and Dojo Nano blog post for more details on building your own version of Dojo.

Conclusion

The guidelines for handling JSON in Dojo 1.7 and 1.8:

  • Parsing pure JSON from a trusted source – Use parse(str) from dojo/json.
  • Parsing JSON from an untrusted source – Use parse(str, true) from dojo/json.
  • Parsing JavaScript expressions (including JSON) from a trusted source – Use dojo.fromJson(str).
  • Serialize objects/values to JSON – Use stringify(value) from dojo/json.
  • Serialize objects/values to JSON with pretty printing – Use stringify(value, " ") from dojo/json.

The new dojo/json module provides a significant performance advantage and code size reduction over dojo.fromJson() and dojo.toJson() on newer browsers, including all relatively recent versions of Chrome, Safari, Firefox, Opera, and IE8 and newer.

Comments

  • Rice Yeh

    How about the functions in dojox.json.ref? Will they be moved to dojo/json?

  • Not in the Dojo 1.x codebase. For Dojo 2.x, we have not yet made decisions on this level yet.

  • RE: #2: Thanks for the reply Zach! Regarding the loop, I will give that a shot. Not being a programmer by trade I would be guinessg that its a for loop? I have seen those in VBA. But then how to incorporate the number into the URL string I enjoy learning this stuff so it should be fun. I assume that I will have to call DownloadJSON2CSV(objArray) 156 times from the for loop but where does the URL go? It would be nice if this could be done from right inside Access (or Excel).As far as the API thing goes, my wife is the only other person who might go near my computer and if she knew what view source was then I’d be shocked. Also, no need to schedule this as I would create a large CSV from these 156 pages one-time. Then I would only call page 1 as the web service seems to sort the data by reverse entry date. So all of the newest entries are on the first page or 2. I am doing the data entry so I will know if I am going past 50 entries and need to run this again but I cant control the output. (i.e. I wish they’d just allow a CSV dump of the data). They add value to the data I am entering so I have to take what I get (JSON) and try to convert it to what I know (CSV).