mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-28 11:56:03 +08:00
perf($interpolate): do not keep empty separators
Do not keep empty separators and keep references to where each expression goes
This commit is contained in:
@@ -188,68 +188,53 @@ function $InterpolateProvider() {
|
||||
var startIndex,
|
||||
endIndex,
|
||||
index = 0,
|
||||
separators = [],
|
||||
expressions = [],
|
||||
parseFns = [],
|
||||
textLength = text.length,
|
||||
hasInterpolation = false,
|
||||
hasText = false,
|
||||
exp,
|
||||
concat = [];
|
||||
concat = [],
|
||||
expressionPositions = [];
|
||||
|
||||
while(index < textLength) {
|
||||
if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
|
||||
((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
|
||||
if (index !== startIndex) hasText = true;
|
||||
separators.push(text.substring(index, startIndex));
|
||||
if (index !== startIndex) {
|
||||
concat.push(unescapeText(text.substring(index, startIndex)));
|
||||
}
|
||||
exp = text.substring(startIndex + startSymbolLength, endIndex);
|
||||
expressions.push(exp);
|
||||
parseFns.push($parse(exp, parseStringifyInterceptor));
|
||||
index = endIndex + endSymbolLength;
|
||||
hasInterpolation = true;
|
||||
expressionPositions.push(concat.length);
|
||||
concat.push('');
|
||||
} else {
|
||||
// we did not find an interpolation, so we have to add the remainder to the separators array
|
||||
if (index !== textLength) {
|
||||
hasText = true;
|
||||
separators.push(text.substring(index));
|
||||
concat.push(unescapeText(text.substring(index)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
forEach(separators, function(key, i) {
|
||||
separators[i] = separators[i].
|
||||
replace(escapedStartRegexp, startSymbol).
|
||||
replace(escapedEndRegexp, endSymbol);
|
||||
});
|
||||
|
||||
if (separators.length === expressions.length) {
|
||||
separators.push('');
|
||||
}
|
||||
|
||||
// Concatenating expressions makes it hard to reason about whether some combination of
|
||||
// concatenated values are unsafe to use and could easily lead to XSS. By requiring that a
|
||||
// single expression be used for iframe[src], object[src], etc., we ensure that the value
|
||||
// that's used is assigned or constructed by some JS code somewhere that is more testable or
|
||||
// make it obvious that you bound the value to some user controlled value. This helps reduce
|
||||
// the load when auditing for XSS issues.
|
||||
if (trustedContext && hasInterpolation && (hasText || expressions.length > 1)) {
|
||||
if (trustedContext && concat.length > 1) {
|
||||
throw $interpolateMinErr('noconcat',
|
||||
"Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
|
||||
"interpolations that concatenate multiple expressions when a trusted value is " +
|
||||
"required. See http://docs.angularjs.org/api/ng.$sce", text);
|
||||
}
|
||||
|
||||
if (!mustHaveExpression || hasInterpolation) {
|
||||
concat.length = separators.length + expressions.length;
|
||||
|
||||
if (!mustHaveExpression || expressions.length) {
|
||||
var compute = function(values) {
|
||||
for(var i = 0, ii = expressions.length; i < ii; i++) {
|
||||
if (allOrNothing && isUndefined(values[i])) return;
|
||||
concat[2*i] = separators[i];
|
||||
concat[(2*i)+1] = values[i];
|
||||
concat[expressionPositions[i]] = values[i];
|
||||
}
|
||||
concat[2*ii] = separators[ii];
|
||||
return concat.join('');
|
||||
};
|
||||
|
||||
@@ -299,7 +284,6 @@ function $InterpolateProvider() {
|
||||
}, {
|
||||
// all of these properties are undocumented for now
|
||||
exp: text, //just for compatibility with regular watchers created via $watch
|
||||
separators: separators,
|
||||
expressions: expressions,
|
||||
$$watchDelegate: function (scope, listener, objectEquality) {
|
||||
var lastValue;
|
||||
@@ -314,6 +298,11 @@ function $InterpolateProvider() {
|
||||
});
|
||||
}
|
||||
|
||||
function unescapeText(text) {
|
||||
return text.replace(escapedStartRegexp, startSymbol).
|
||||
replace(escapedEndRegexp, endSymbol);
|
||||
}
|
||||
|
||||
function parseStringifyInterceptor(value) {
|
||||
try {
|
||||
return stringify(getValue(value));
|
||||
|
||||
@@ -7,7 +7,6 @@ describe('$interpolate', function() {
|
||||
var interpolateFn = $interpolate('some text');
|
||||
|
||||
expect(interpolateFn.exp).toBe('some text');
|
||||
expect(interpolateFn.separators).toEqual(['some text']);
|
||||
expect(interpolateFn.expressions).toEqual([]);
|
||||
|
||||
expect(interpolateFn({})).toBe('some text');
|
||||
@@ -41,7 +40,6 @@ describe('$interpolate', function() {
|
||||
var interpolateFn = $interpolate('Hello {{name}}!');
|
||||
|
||||
expect(interpolateFn.exp).toBe('Hello {{name}}!');
|
||||
expect(interpolateFn.separators).toEqual(['Hello ', '!']);
|
||||
expect(interpolateFn.expressions).toEqual(['name']);
|
||||
|
||||
var scope = $rootScope.$new();
|
||||
@@ -185,7 +183,6 @@ describe('$interpolate', function() {
|
||||
}));
|
||||
|
||||
it('should not get confused with same markers', inject(function($interpolate) {
|
||||
expect($interpolate('---').separators).toEqual(['---']);
|
||||
expect($interpolate('---').expressions).toEqual([]);
|
||||
expect($interpolate('----')({})).toEqual('');
|
||||
expect($interpolate('--1--')({})).toEqual('1');
|
||||
@@ -194,67 +191,58 @@ describe('$interpolate', function() {
|
||||
|
||||
describe('parseBindings', function() {
|
||||
it('should Parse Text With No Bindings', inject(function($interpolate) {
|
||||
expect($interpolate("a").separators).toEqual(['a']);
|
||||
expect($interpolate("a").expressions).toEqual([]);
|
||||
}));
|
||||
|
||||
it('should Parse Empty Text', inject(function($interpolate) {
|
||||
expect($interpolate("").separators).toEqual(['']);
|
||||
expect($interpolate("").expressions).toEqual([]);
|
||||
}));
|
||||
|
||||
it('should Parse Inner Binding', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("a{{b}}C"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['a', 'C']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b']);
|
||||
expect(interpolateFn({b: 123})).toEqual('a123C');
|
||||
}));
|
||||
|
||||
it('should Parse Ending Binding', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("a{{b}}"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['a', '']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b']);
|
||||
expect(interpolateFn({b: 123})).toEqual('a123');
|
||||
}));
|
||||
|
||||
it('should Parse Begging Binding', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("{{b}}c"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['', 'c']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b']);
|
||||
expect(interpolateFn({b: 123})).toEqual('123c');
|
||||
}));
|
||||
|
||||
it('should Parse Loan Binding', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("{{b}}"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['', '']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b']);
|
||||
expect(interpolateFn({b: 123})).toEqual('123');
|
||||
}));
|
||||
|
||||
it('should Parse Two Bindings', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("{{b}}{{c}}"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['', '', '']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b', 'c']);
|
||||
expect(interpolateFn({b: 111, c: 222})).toEqual('111222');
|
||||
}));
|
||||
|
||||
it('should Parse Two Bindings With Text In Middle', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate("{{b}}x{{c}}"),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['', 'x', '']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['b', 'c']);
|
||||
expect(interpolateFn({b: 111, c: 222})).toEqual('111x222');
|
||||
}));
|
||||
|
||||
it('should Parse Multiline', inject(function($interpolate) {
|
||||
var interpolateFn = $interpolate('"X\nY{{A\n+B}}C\nD"'),
|
||||
separators = interpolateFn.separators, expressions = interpolateFn.expressions;
|
||||
expect(separators).toEqual(['"X\nY', 'C\nD"']);
|
||||
expressions = interpolateFn.expressions;
|
||||
expect(expressions).toEqual(['A\n+B']);
|
||||
expect(interpolateFn({'A': 'aa', 'B': 'bb'})).toEqual('"X\nYaabbC\nD"');
|
||||
}));
|
||||
@@ -317,7 +305,6 @@ describe('$interpolate', function() {
|
||||
});
|
||||
|
||||
inject(function($interpolate) {
|
||||
expect($interpolate('---').separators).toEqual(['---']);
|
||||
expect($interpolate('---').expressions).toEqual([]);
|
||||
expect($interpolate('----')({})).toEqual('');
|
||||
expect($interpolate('--1--')({})).toEqual('1');
|
||||
|
||||
Reference in New Issue
Block a user