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

Commit aafb9d9

Browse files
committed
perf(ngClass): optimize the case of static map of classes with large objects by refactor
1 parent 51a2eb7 commit aafb9d9

File tree

1 file changed

+48
-30
lines changed

1 file changed

+48
-30
lines changed

src/ng/directive/ngClass.js

+48-30
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,33 @@
88

99
function classDirective(name, selector) {
1010
name = 'ngClass' + name;
11-
return ['$animate', function($animate) {
11+
return ['$animate','$parse', function($animate,$parse) {
1212
return {
1313
restrict: 'AC',
1414
link: function(scope, element, attr) {
15-
var oldVal;
15+
var oldClasses;
1616

17-
scope.$watch(attr[name], ngClassWatchAction, true);
17+
var classFn = $parse(attr[name], arrayClasses);
18+
scope.$watch(classFn, ngClassWatchAction, true);
1819

1920
attr.$observe('class', function(value) {
20-
ngClassWatchAction(scope.$eval(attr[name]));
21+
ngClassWatchAction(classFn(scope));
2122
});
2223

2324

2425
if (name !== 'ngClass') {
2526
scope.$watch('$index', function($index, old$index) {
26-
/* eslint-disable no-bitwise */
27+
// eslint-disable-next-line no-bitwise
2728
var mod = $index & 1;
29+
// eslint-disable-next-line no-bitwise
2830
if (mod !== (old$index & 1)) {
29-
var classes = arrayClasses(scope.$eval(attr[name]));
3031
if (mod === selector) {
31-
addClasses(classes);
32+
ngClassWatchAction(classFn(scope));
3233
} else {
33-
removeClasses(classes);
34+
removeClasses(oldClasses);
35+
oldClasses = [];
3436
}
3537
}
36-
/* eslint-enable */
3738
});
3839
}
3940

@@ -80,18 +81,13 @@ function classDirective(name, selector) {
8081
function ngClassWatchAction(newVal) {
8182
// eslint-disable-next-line no-bitwise
8283
if (selector === true || (scope.$index & 1) === selector) {
83-
var newClasses = arrayClasses(newVal || []);
84-
if (!oldVal) {
84+
var newClasses = (newVal || []).join(' ').split(' ');
85+
if (!oldClasses) {
8586
addClasses(newClasses);
86-
} else if (!equals(newVal,oldVal)) {
87-
var oldClasses = arrayClasses(oldVal);
87+
} else if (!arrayEqualClasses(oldClasses, newClasses)) {
8888
updateClasses(oldClasses, newClasses);
8989
}
90-
}
91-
if (isArray(newVal)) {
92-
oldVal = newVal.map(function(v) { return shallowCopy(v); });
93-
} else {
94-
oldVal = shallowCopy(newVal);
90+
oldClasses = shallowCopy(newClasses);
9591
}
9692
}
9793
}
@@ -112,24 +108,46 @@ function classDirective(name, selector) {
112108
}
113109

114110
function arrayClasses(classVal) {
115-
var classes = [];
111+
var classes;
116112
if (isArray(classVal)) {
117-
forEach(classVal, function(v) {
118-
classes = classes.concat(arrayClasses(v));
119-
});
120-
return classes;
121-
} else if (isString(classVal)) {
122-
return classVal.split(' ');
113+
classes = classVal.map(classNames);
123114
} else if (isObject(classVal)) {
124-
forEach(classVal, function(v, k) {
125-
if (v) {
126-
classes = classes.concat(k.split(' '));
115+
classes = [];
116+
forEach(classVal, function(val, key) {
117+
if (val) {
118+
classes.push(key);
119+
} else if (isUndefined(val)) {
120+
// This case is for one time binding:
121+
// ::expression are evaluated until no undefineds are found
122+
// if no undefined is placed inside the array,
123+
// it would assume that the value is fully computed and will fail
124+
classes.push(val);
127125
}
128126
});
129-
return classes;
127+
} else if (isString(classVal)) {
128+
classes = [classVal];
129+
} else {
130+
classes = classVal;
130131
}
131-
return classVal;
132+
133+
return classes;
132134
}
135+
136+
function classNames(values) {
137+
if (isObject(values)) {
138+
return Object.keys(values).filter(function(k) {
139+
return values[k];
140+
}).join(' ');
141+
} else {
142+
return values;
143+
}
144+
}
145+
146+
function arrayEqualClasses(a1, a2) {
147+
return a1 === a2 ||
148+
isArray(a1) && isArray(a2) && a1.join(' ') === a2.join(' ');
149+
}
150+
133151
}];
134152
}
135153

0 commit comments

Comments
 (0)