diff options
| author | Igor Minar | 2010-12-22 13:19:26 -0800 | 
|---|---|---|
| committer | Igor Minar | 2010-12-22 14:16:36 -0800 | 
| commit | e7a0fb250f6cc69c93daffe0d043d073fd488c03 (patch) | |
| tree | a799e9264a131a9124de7983b5655b9e97df44ba | |
| parent | e3ddc2bcc48ba6160455c4ffe35df87715c05693 (diff) | |
| download | angular.js-e7a0fb250f6cc69c93daffe0d043d073fd488c03.tar.bz2 | |
fromJson delegation to native JSON parser if available
- native parser delegation
- $xhr change to use native parser
| -rw-r--r-- | perf/jsonPerfSpec.js | 51 | ||||
| -rw-r--r-- | src/Angular.js | 3 | ||||
| -rw-r--r-- | src/JSON.js | 28 | ||||
| -rw-r--r-- | src/parser.js | 2 | ||||
| -rw-r--r-- | src/services.js | 2 | ||||
| -rw-r--r-- | test/JsonSpec.js | 36 | 
6 files changed, 77 insertions, 45 deletions
| diff --git a/perf/jsonPerfSpec.js b/perf/jsonPerfSpec.js index c232aed8..01a489e2 100644 --- a/perf/jsonPerfSpec.js +++ b/perf/jsonPerfSpec.js @@ -1,55 +1,28 @@  describe('json', function() { -  xit('should parse json in a reasonable time', function() { -    var totalSubstr = 0, -        totalGetMatch = 0, -        totalConsume = 0, -        totalTime = 0, -        runTimes = []; -     -    for (var i=0; i<10; i++) { -      window.substrTime = 0; -      window.getMatchTime = 0; -      window.consumeTime = 0; -      var start = Date.now(); -      expect(angular.fromJson(largeJsonString)).toBeTruthy(); -      var time = Date.now() - start; -//      dump('parse time', time, 'consume', window.consumeTime, -//                               'substr', window.substrTime, -//                               'getMatch', window.getMatchTime); -      totalTime += time; -      totalSubstr += window.substrTime; -      totalGetMatch += window.getMatchTime; -      totalConsume += window.consumeTime; -      runTimes.push(time); -    } - -    totalGetMatch = totalGetMatch - totalSubstr; - -    dump("totals", totalTime, -          "| consume", totalConsume, '' + Math.round(totalConsume/(totalTime/100)) + '%', -          "| substr", totalSubstr, '' + Math.round(totalSubstr/(totalTime/100)) + '%', -          "| getMatch", totalGetMatch, '' + Math.round(totalGetMatch/(totalTime/100)) + '%'); -    dump("run times", runTimes); -    delete window.consumeTime; -    delete window.substrTime; -    delete window.getMatchTime; -  }); -    it('angular parser', function() {      var duration = time(function() {        expect(angular.fromJson(largeJsonString)).toBeTruthy();      }, 1); -    expect(duration).toBeLessThan(4000); +    dump(duration/1 + ' ms per iteration'); +  }); + + +  it('angular delegating to native parser', function() { +    var duration = time(function() { +      expect(angular.fromJson(largeJsonString, true)).toBeTruthy(); +    }, 100); + +    dump(duration/100 + ' ms per iteration');    });    it('native json', function() {      var duration = time(function() {        expect(JSON.parse(largeJsonString)).toBeTruthy(); -    }, 1); +    }, 100); -    expect(duration).toBeLessThan(200); +    dump(duration/100 + ' ms per iteration');    });  }); diff --git a/src/Angular.js b/src/Angular.js index ea5d1ea1..991598e1 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -109,7 +109,8 @@ var _undefined        = undefined,      angularService    = extensionMap(angular, 'service'),      angularCallbacks  = extensionMap(angular, 'callbacks'),      nodeName, -    rngScript         = /^(|.*\/)angular(-.*?)?(\.min)?.js(\?[^#]*)?(#(.*))?$/; +    rngScript         = /^(|.*\/)angular(-.*?)?(\.min)?.js(\?[^#]*)?(#(.*))?$/, +    DATE_ISOSTRING_LN = 24;  /**   * @workInProgress diff --git a/src/JSON.js b/src/JSON.js index 2906362c..399b2197 100644 --- a/src/JSON.js +++ b/src/JSON.js @@ -29,19 +29,41 @@ function toJson(obj, pretty) {   * Deserializes a string in the JSON format.   *   * @param {string} json JSON string to deserialize. + * @param {boolean} [useNative=false] Use native JSON parser if available   * @returns {Object|Array|Date|string|number} Deserialized thingy.   */ -function fromJson(json) { +function fromJson(json, useNative) {    if (!json) return json; + +  var obj, p, expression; +    try { -    var p = parser(json, true); -    var expression =  p.primary(); +    if (useNative && JSON && JSON.parse) { +      obj = JSON.parse(json); +      return transformDates(obj); +    } + +    p = parser(json, true); +    expression =  p.primary();      p.assertAllConsumed();      return expression(); +    } catch (e) {      error("fromJson error: ", json, e);      throw e;    } + +  // TODO make foreach optionally recursive and remove this function +  function transformDates(obj) { +    if (isString(obj) && obj.length === DATE_ISOSTRING_LN) { +      return angularString.toDate(obj); +    } else if (isArray(obj) || isObject(obj)) { +      foreach(obj, function(val, name) { +        obj[name] = transformDates(val); +      }); +    } +    return obj; +  }  }  angular['toJson'] = toJson; diff --git a/src/parser.js b/src/parser.js index a9b66c52..d233b15f 100644 --- a/src/parser.js +++ b/src/parser.js @@ -26,7 +26,7 @@ var OPERATORS = {  var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};  function lex(text, parseStringsForObjects){ -  var dateParseLength = parseStringsForObjects ? 24 : -1, +  var dateParseLength = parseStringsForObjects ? DATE_ISOSTRING_LN : -1,        tokens = [],        token,        index = 0, diff --git a/src/services.js b/src/services.js index d49b5370..36c43564 100644 --- a/src/services.js +++ b/src/services.js @@ -705,7 +705,7 @@ angularServiceInject('$xhr', function($browser, $error, $log){      $browser.xhr(method, url, post, function(code, response){        try {          if (isString(response) && /^\s*[\[\{]/.exec(response) && /[\}\]]\s*$/.exec(response)) { -          response = fromJson(response); +          response = fromJson(response, true);          }          if (code == 200) {            callback(code, response); diff --git a/test/JsonSpec.js b/test/JsonSpec.js index ba3366e5..6d8a40e4 100644 --- a/test/JsonSpec.js +++ b/test/JsonSpec.js @@ -116,6 +116,42 @@ describe('json', function(){      expect(fromJson("{exp:1.2e-10}")).toEqual({exp:1.2E-10});    }); + +  //run these tests only in browsers that have native JSON parser +  if (JSON && JSON.parse) { + +    describe('native parser', function() { + +      var nativeParser = JSON.parse; + +      afterEach(function() { +        JSON.parse = nativeParser; +      }); + + +      it('should delegate to native parser if available and boolean flag is passed', function() { +        var spy = this.spyOn(JSON, 'parse').andCallThrough(); + +        expect(fromJson('{}')).toEqual({}); +        expect(spy).wasNotCalled(); + +        expect(fromJson('{}', true)).toEqual({}); +        expect(spy).wasCalled(); +      }); + + +      it('should convert timestamp strings to Date objects', function() { +        expect(fromJson('"2010-12-22T17:23:17.974Z"', true) instanceof Date).toBe(true); +        expect(fromJson('["2010-12-22T17:23:17.974Z"]', true)[0] instanceof Date).toBe(true); +        expect(fromJson('{"t":"2010-12-22T17:23:17.974Z"}', true).t instanceof Date).toBe(true); +        expect(fromJson('{"t":["2010-12-22T17:23:17.974Z"]}', true).t[0] instanceof Date).toBe(true); +        expect(fromJson('{"t":{"t":"2010-12-22T17:23:17.974Z"}}', true).t.t instanceof Date).toBe(true); +      }); +    }); + +  } + +    describe('security', function(){      it('should not allow naked expressions', function(){        expect(function(){fromJson('1+2');}). | 
