The more I learn about JavaScript, the more I love it. We can offload a lot of processing for web applications from the server to the browser, doing the coding in JavaScript instead of PHP, Python or Java.
But, in order to do the data processing with JavaScript, we need a good data representation that is easy to process in JavaScript. JSON is that notation.
With JSON, we can:
We did all but the last of these in Tandora, and we planned to do the last one (but just ran out of time). The result was lightning-fast searching and sorting.
It's a hierarchical structure consisting of
We'll take a few minutes to explore Tandora. Before we get to the code, here's the basic idea:
display
property to none
for elements we don't want, but we didn't think of that (or, rather,
we worried about interaction with other code).
sort
method, and then
re-format the array again.
Okay, let's get a little glimpse of the code.
book, in JSON format. In this case, we could use a simple file, since this part of the data is read-only (users won't modify it). Thus, it requires zero database processing to produce this data. It can even be cached.
jQuery(document).ready( ... )
getPresentationResults
getPresentationResults
in presentations-sortable.js. (It's
at the end; go to the end and scroll backwards).
receiveResults()
.
redoPresentationResults
. This formats the
presentations, but then re-creates the event handlers for all of
them.
smallResult
, which is the same
as resultTemplate
. (The connection between these
functions and the presentationResults
object isn't
obvious, but the object can be given a function to format (stringify)
each selected and sorted element.) You can
find resultTemplate
near the top
of presentations-sortable.js.
detailTemplate
in presentations-detail.js.
.json
file we looked at above is created by a PHP
script. Most of the code of this file is just constructing the query
results. Turning it into JSON is trivial, thanks to the
PHP json_encode
function. This function is invoked at the end of the script.
Okay, so loading JSON data is easy and cool. But there's trouble getting data from different servers due to a browser security issue, namely the Same Origin Policy, which is that the browser will not grant an Ajax request to a different server.
Here's a variation on that human-readable version only this one tries to get the data from http://www.scott-anderson.org/demos/presentations.json, which is a different server:
We'll all look, using Firebug, at what happens in this case: the request is silently ignored. No error message, just no data.
A clever work-around to the Same Origin Policy is called JSONP. It can make your head hurt, but here's the basic idea:
script
element is exempt from the policy.
The src
attribute of a script
element can
reference any server. (That's how you can load jQuery from the CDN or
Google servers, for example.)
<script src="http://any.site.com/path/to/file"></script>
script
element will execute whatever code is
retrieved via the src
attribute.
<script>["Peter Jackson","David Lean","Akira Kurosawa"]</script>
<script>fred(["Peter Jackson","David Lean","Akira Kurosawa"])</script>
fred
function like this,
you could process the data. This function is the callback
function.
Here's a working example:
Here's the script element:
But, of course, that has no effect. Instead, we need to wrap the result in something, so we need a different PHP script:
Let's see it in action:
One last step: This is all well and good, but we'd like to dynamically
create these JSONP requests. Well, we can once we realize that
we can dynamically add script
elements to a page.
That's what
the jQuery.getJSON()
method does.
Not surprisingly, JSON is easy to handle in JavaScript:
>>> fred = {"name": "fred", "brother":"george", "hair":"red"} >>> fred.brother "george" >>> prop = "hair" >>> fred[prop] "red" >>> for( p in fred ) { console.log(fred[p]); } >>> "george" >>> "red" >>> "fred"
>>> weasleys = ["bill","charlie","percy","fred","george","ron","ginnie"] >>> weasleys.length 7 >>> weasleys[3] "fred"
>>>var what = Object.prototype.toString; >>> what.call("fred") "[object String]" >>> what.call(3) "[object Number]" >>> what.call([3]) "[object Array]" >>> what.call({a:3)) "[object Object]" >>> what.call(true); "[object Boolean]" >>> what.call(false); "[object Boolean]" >>> what.call(null); "[object Null]"
eval()
, but don't. If there's nefarious
code in there, it'll be executed. Instead, use:
var x = JSON.parse('{"a":1,"b":2}'); var y = JSON.stringify(x);
We've seen that there is nice support for JSON notation in PHP
When traversing a JSON data structure, it's helpful to know about gettype,
Similarly, there is good support for JSON notation in Python thanks to the JSON module.
This isn't too surprising, since a Python dictionary is the same thing as a JSON object, and all the other data (arrays, numbers, strings) translate easily.
For type checking in Python, try type(o)
and isinstance(o,type)
There are many packages for processing JSON in Java. One by Douglas Crockford himself is JSON in Java.
I wrote an example of it in action, traversing a JSON entity to pretty-print it.
The basic idea:
pprint
method that is polymorphic:
The code:
cd ~cs304/pub/servlets/WEB-INF/classes java JSONpprint | more
Using your favorite language, write some pseudo-code for counting the number of atoms in a JSON data structure.
Once you can do this, you can do pretty much anything: search for something, modify the data structure, etc.
There are 6221 atoms in the Tandora book.