Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit d302ea0

Browse files
committed
perf($parse): use no-proto maps as caches and avoid hasOwnProperty checks
1 parent a09fa35 commit d302ea0

File tree

5 files changed

+21
-29
lines changed

5 files changed

+21
-29
lines changed

src/.jshintrc

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"assertNotHasOwnProperty": false,
8787
"getter": false,
8888
"getBlockNodes": false,
89+
"createMap": false,
8990
"VALIDITY_STATE_PROPERTY": false,
9091

9192
"skipDestroyOnNextJQueryCleanData": true,

src/Angular.js

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
getter: true,
8484
getBlockNodes: true,
8585
hasOwnProperty: true,
86+
createMap: true,
8687
*/
8788

8889
////////////////////////////////////

src/ng/parse.js

+17-28
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ function ensureSafeFunction(obj, fullExpression) {
8080
}
8181
}
8282

83-
var OPERATORS = {
83+
var OPERATORS = extend(createMap(), {
8484
/* jshint bitwise : false */
8585
'null':function(){return null;},
8686
'true':function(){return true;},
@@ -118,7 +118,7 @@ var OPERATORS = {
118118
// '|':function(self, locals, a,b){return a|b;},
119119
'|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
120120
'!':function(self, locals, a){return !a(self, locals);}
121-
};
121+
});
122122
/* jshint bitwise: true */
123123
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
124124

@@ -301,9 +301,10 @@ Lexer.prototype = {
301301
text: ident
302302
};
303303

304-
// OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
305-
if (OPERATORS.hasOwnProperty(ident)) {
306-
token.fn = OPERATORS[ident];
304+
var fn = OPERATORS[ident];
305+
306+
if (fn) {
307+
token.fn = fn;
307308
token.constant = true;
308309
} else {
309310
var getter = getterFn(ident, this.options, this.text);
@@ -834,7 +835,7 @@ function setter(obj, path, setValue, fullExp) {
834835
return setValue;
835836
}
836837

837-
var getterFnCache = {};
838+
var getterFnCache = createMap();
838839

839840
/**
840841
* Implementation of the "Black Hole" variant from:
@@ -875,16 +876,12 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp) {
875876
}
876877

877878
function getterFn(path, options, fullExp) {
878-
// Check whether the cache has this getter already.
879-
// We can use hasOwnProperty directly on the cache because we ensure,
880-
// see below, that the cache never stores a path called 'hasOwnProperty'
881-
if (getterFnCache.hasOwnProperty(path)) {
882-
return getterFnCache[path];
883-
}
879+
var fn = getterFnCache[path];
880+
881+
if (fn) return fn;
884882

885883
var pathKeys = path.split('.'),
886-
pathKeysLength = pathKeys.length,
887-
fn;
884+
pathKeysLength = pathKeys.length;
888885

889886
// http://jsperf.com/angularjs-parse-getter/6
890887
if (options.csp) {
@@ -923,11 +920,7 @@ function getterFn(path, options, fullExp) {
923920
fn = evaledFnGetter;
924921
}
925922

926-
// Only cache the value if it's not going to mess up the cache object
927-
// This is more performant that using Object.prototype.hasOwnProperty.call
928-
if (path !== 'hasOwnProperty') {
929-
getterFnCache[path] = fn;
930-
}
923+
getterFnCache[path] = fn;
931924
return fn;
932925
}
933926

@@ -984,7 +977,7 @@ function getterFn(path, options, fullExp) {
984977
* service.
985978
*/
986979
function $ParseProvider() {
987-
var cache = {};
980+
var cache = createMap();
988981

989982
var $parseOptions = {
990983
csp: false
@@ -1001,9 +994,9 @@ function $ParseProvider() {
1001994
case 'string':
1002995
cacheKey = exp = exp.trim();
1003996

1004-
if (cache.hasOwnProperty(cacheKey)) {
1005-
parsedExpression = cache[cacheKey];
1006-
} else {
997+
parsedExpression = cache[cacheKey];
998+
999+
if (!parsedExpression) {
10071000
if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
10081001
oneTime = true;
10091002
exp = exp.substring(2);
@@ -1020,11 +1013,7 @@ function $ParseProvider() {
10201013
oneTimeLiteralWatch : oneTimeWatch;
10211014
}
10221015

1023-
if (cacheKey !== 'hasOwnProperty') {
1024-
// Only cache the value if it's not going to mess up the cache object
1025-
// This is more performant that using Object.prototype.hasOwnProperty.call
1026-
cache[cacheKey] = parsedExpression;
1027-
}
1016+
cache[cacheKey] = parsedExpression;
10281017
}
10291018
return addInterceptor(parsedExpression, interceptorFn);
10301019

test/.jshintrc

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"assertNotHasOwnProperty": false,
8484
"getter": false,
8585
"getBlockElements": false,
86+
"createMap": false,
8687
"VALIDITY_STATE_PROPERTY": true,
8788

8889
/* AngularPublic.js */

test/ng/parseSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ describe('parser', function() {
55
beforeEach(function() {
66
/* global getterFnCache: true */
77
// clear cache
8-
getterFnCache = {};
8+
getterFnCache = createMap();
99
});
1010

1111

0 commit comments

Comments
 (0)