aboutsummaryrefslogtreecommitdiffstats
path: root/src/ng/parse.js
diff options
context:
space:
mode:
authorKarl Seamon2013-12-05 18:08:52 -0500
committerIgor Minar2013-12-18 15:44:15 -0800
commit864b2596b246470cca9d4e223eaed720f4462319 (patch)
tree1b86f335f5afc3b21217fa3d8ab327718112db2e /src/ng/parse.js
parentf3a796e522afdbd3b640d14426edb2fbfab463c5 (diff)
downloadangular.js-864b2596b246470cca9d4e223eaed720f4462319.tar.bz2
perf($parse) use a faster path when the number of path parts is low
Use a faster path when the number of path tokens is low (ie the common case). This results in a better than 19x improvement in the time spent in $parse and produces output that is about the same speed in chrome and substantially faster in firefox. http://jsperf.com/angularjs-parse-getter/6 Closes #5359
Diffstat (limited to 'src/ng/parse.js')
-rw-r--r--src/ng/parse.js60
1 files changed, 43 insertions, 17 deletions
diff --git a/src/ng/parse.js b/src/ng/parse.js
index 8b3f145a..50462e43 100644
--- a/src/ng/parse.js
+++ b/src/ng/parse.js
@@ -891,19 +891,19 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
? function cspSafeGetter(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
- if (pathVal === null || pathVal === undefined) return pathVal;
+ if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
- if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key1 || pathVal == null) return pathVal;
pathVal = pathVal[key1];
- if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key2 || pathVal == null) return pathVal;
pathVal = pathVal[key2];
- if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key3 || pathVal == null) return pathVal;
pathVal = pathVal[key3];
- if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key4 || pathVal == null) return pathVal;
pathVal = pathVal[key4];
return pathVal;
@@ -912,7 +912,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
promise;
- if (pathVal === null || pathVal === undefined) return pathVal;
+ if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (pathVal && pathVal.then) {
@@ -924,7 +924,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key1 || pathVal == null) return pathVal;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
@@ -936,7 +936,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key2 || pathVal == null) return pathVal;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
@@ -948,7 +948,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key3 || pathVal == null) return pathVal;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
@@ -960,7 +960,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
+ if (!key4 || pathVal == null) return pathVal;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
@@ -976,6 +976,27 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
};
}
+function simpleGetterFn1(key0, fullExp) {
+ ensureSafeMemberName(key0, fullExp);
+
+ return function simpleGetterFn1(scope, locals) {
+ if (scope == null) return scope;
+ return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
+ };
+}
+
+function simpleGetterFn2(key0, key1, fullExp) {
+ ensureSafeMemberName(key0, fullExp);
+ ensureSafeMemberName(key1, fullExp);
+
+ return function simpleGetterFn2(scope, locals) {
+ if (scope == null) return scope;
+ scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
+
+ return scope == null ? scope : scope[key1];
+ };
+}
+
function getterFn(path, options, fullExp) {
// Check whether the cache has this getter already.
// We can use hasOwnProperty directly on the cache because we ensure,
@@ -988,7 +1009,13 @@ function getterFn(path, options, fullExp) {
pathKeysLength = pathKeys.length,
fn;
- if (options.csp) {
+ // When we have only 1 or 2 tokens, use optimized special case closures.
+ // http://jsperf.com/angularjs-parse-getter/6
+ if (!options.unwrapPromises && pathKeysLength === 1) {
+ fn = simpleGetterFn1(pathKeys[0], fullExp);
+ } else if (!options.unwrapPromises && pathKeysLength === 2) {
+ fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
+ } else if (options.csp) {
if (pathKeysLength < 6) {
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
options);
@@ -1006,11 +1033,10 @@ function getterFn(path, options, fullExp) {
};
}
} else {
- var code = 'var l, fn, p;\n';
+ var code = 'var p;\n';
forEach(pathKeys, function(key, index) {
ensureSafeMemberName(key, fullExp);
- code += 'if(s === null || s === undefined) return s;\n' +
- 'l=s;\n' +
+ code += 'if(s == null) return s;\n' +
's='+ (index
// we simply dereference 's' on any .dot notation
? 's'
@@ -1033,10 +1059,10 @@ function getterFn(path, options, fullExp) {
/* jshint -W054 */
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
/* jshint +W054 */
- evaledFnGetter.toString = function() { return code; };
- fn = function(scope, locals) {
+ evaledFnGetter.toString = valueFn(code);
+ fn = options.unwrapPromises ? function(scope, locals) {
return evaledFnGetter(scope, locals, promiseWarning);
- };
+ } : evaledFnGetter;
}
// Only cache the value if it's not going to mess up the cache object