An Alternative to AJAX for Large Data Sets
At the moment I am buried deep in Google Gears. As part of this exercise I am having to find the best way of going offline with a large amount of data and then putting any changes back online.
Because I'm dealing with handheld devices the ideal option is to simply download everything in one go, so as to avoid the overhead of numerous connections. GPRS is sloooooow.
The trouble I've found with downloading large amounts of JSON data is that the eval() call you need to work with it can run in to issues as the amount of data approaches and/or passes about the 64kb mark.
The way round this I've found is to use the Dynamic Script Tag technique. Although I've heard of it in the past, this was the first time I'd used it and was impressed with how much easier it is than Ajax and thought you guys might like to hear about it.
Dynamic Script Tags?
As the name suggests this technique simply adds a <script> tag to your document's <head> element dynamically. When you add the Script element the browser fetches the JavaScript and, once downloaded, it executes directly in the browser.
As a simple example, imagine you add a <script> tag which points to an agent. In the agent you use a couple of print statements, like so:
Print "content-type: text/javascript" Print "alert('Hello, world!');"
It doesn't take a genius to work out what happens. As soon as the agent is done the content of the <script> tag runs and the user sees an alert dialog saying hello.
Already you should be seeing how this is different to Ajax. No?
Taking it one step further you can have the JavaScript returned run your own functions. Imagine an agent that printed lines like this:
Print "content-type: text/javascript" Print "myFunction({" Print " documents: [{id:'doc1'},{id:'doc2'}]" Print "});"
In this case the browser would call the "myFunction" function when it loaded the script file. You would have to define this function on your page and tell it what to do with the JSON object you're passing to it.
Adding the Script Tag
To get the browser to dynamically add the <script> tag we simply use some code like the following JavaScript:
var script=document.createElement('script'); script.setAttribute("src",url); script.setAttribute("type","text/javascript"); document.getElementsByTagName('head')[0].appendChild(script);
It should be fairly obvious what that does.
Example
Here's an example of the technique in use. Press the "fetch view" button and it should load a set of documents.
Using something like Firebug you should be able to inspect the DOM before and after pressing the "fetch view" button to see how it added an extra script element to the head. The rest of the code used is inline in the page source if you're interested.
Summary
As always it's horses for courses and whether you use this technique over Ajax is down to your requirements.
One obvious benefit to this technique is that you can fetch data from another domain, whereas Ajax won't allow this and you usually need to build a proxy to do so.
Drawbacks to this technique include not being able to POST data and not being able to monitor for timeouts and 404 errors etc. You just insert the Script tag and hope...
Hey Jake,
I've used a similar technique in the past to load large datasets, but relied more on a specific NotesDocument and a defined RichTextItem to do the "heavy lifting" for me.
In one particular example, I would "cache" the dataset into a logic-driven UNID NotesDocument (password-hash "index"), and create NotesItems that contain the markup that I needed.
(In your case, one would contain the <script>myFunction...</script> content.)
At this point, it's a matter of calling that NotesDocument and grabbing the full index of NotesDocuments (which has been updated in the backend, you're just grabbing a given NotesItem contents) that build your dataset, and then doing the DST work to add it into the header.
The benefit to this approach is not only the speed (NotesDocument vs. Agent), but you can also move to a "permalink" solution for accessing the "index" NotesDocuments, leverage Readers fields, and provide secured dataset access.
-Chris
Chris Heilmann posted a similar tidbit today:
http://feedproxy.google.com/~r/wait-till-i/gwZf/~3/dP6G-psgls4/
In the API he describes, even the function name is dynamic - you pass it in as a parameter to the URL that generates the script tag, and the resulting script checks to see if the function name you specified is a defined function, and if it is, it calls it. So you could use the same dynamic endpoint for multiple uses just by defining multiple callback functions.
And this does work in a cross-domain context.