views:

115

answers:

3

I'm using slightly modified sample code provided by the YUI team. When my source responds with something other than JSON (or just has a JSON syntax error) my browser (Safari) aborts script processing, preventing me from notifying the user there was a problem.

I'm definitely no JS guru, so this code may be a lot uglier than it has to be. The code is, roughly:

YUI().use("dump", "node", "datasource-get", "datasource-jsonschema", function(Y) {
  var myDataSource = new Y.DataSource.Get({
    source:"/some/json/source/?"}),
    myCallback = {
      success: function(e){
        myResponse = e.response;
        doSomething(myDataSource);
      },
      failure: function(e){
        Y.get("#errors").setContent("<li>Could not retrieve data: " + e.error.message + "</li>");
      }
    };

  myDataSource.plug(Y.Plugin.DataSourceJSONSchema, {
    schema: {
      resultListLocator: "blah.list",
      resultFields: ["user", "nickname"]
    }
  });
  myDataSource.sendRequest("foo=bar", myCallback);
}

I've tried wrapping the "var myDataSource" block in a try/catch, and I've also tried wrapping the whole YUI().use() block.

Is it possible to catch syntax errors? Do I have to replace the all-in-one DataSource.Get call with separate IO and parse calls?

A: 

Maybe try this before you "doSomething":

try
{
   var test = YAHOO.lang.JSON.parse(jsonString); 
   ...
}
catch (e)
{
   alert('invalid json');
}
Paul U
+1  A: 

The problem is probably that the error happens at some level in the browser (Javascript parsing) before YUI even gets the occasion to report a failure.

It is notoriously hard to catch this kind of error in Safari, which does not implement window.onerror. In order to catch more errors with my Javascript library, bezen.org, I added try/catch in places where asynchronous code is triggered:

  • dynamic script loading (equivalent to your JSON download)
  • setTimeout/setTimer: I wrapped and replaced these browser functions to insert a try/catch which logs errors

You may be interested in having a look at the source code of the corresponding modules, which may be useful to you as is or as hints for the resolution of your problem:

Eric Bréchemier
+1  A: 

Since you are requesting a local script, you can use Y.io + Y.JSON.parse inside a try/catch or Y.DataSource.IO + Y.DataSchema.JSON (+ Y.JSON).

The benefit of DataSource.Get is that it avoids the Same Origin Policy. However, it is less secure and less flexible. If it is not necessary, you should avoid using it.

The contract of DataSource.Get is that the server supports JSONP. The way this works is that Get adds a script node to the page with a src=(the url you provided)&callback=someDataSourceFunction.

The browser will request the resource at that url and one of two things will happen:

  1. the server will respond with a JavaScript string in the form of someDataSourceFunction({"all":"your data"}); or
  2. the server will return some text that can't be parsed as JavaScript.

In either event, that string is treated as the contents of a script node--it is parsed and executed. If it cannot be parsed, the browser will throw an error. There's no stopping this. While JSONP is technically not under the spec constraints of true JSON (even invalid JSON should parse and execute), you should always use pure JSON, and always use a server side lib to generate the JSON output (look on http://json.org for a list of libs in every conceivable language). Don't hand-roll JSON. It only leads to hours of debugging.

Luke