aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Minar2010-12-22 13:19:26 -0800
committerIgor Minar2010-12-22 14:16:36 -0800
commite7a0fb250f6cc69c93daffe0d043d073fd488c03 (patch)
treea799e9264a131a9124de7983b5655b9e97df44ba
parente3ddc2bcc48ba6160455c4ffe35df87715c05693 (diff)
downloadangular.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.js51
-rw-r--r--src/Angular.js3
-rw-r--r--src/JSON.js28
-rw-r--r--src/parser.js2
-rw-r--r--src/services.js2
-rw-r--r--test/JsonSpec.js36
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');}).