-
Notifications
You must be signed in to change notification settings - Fork 27.4k
perf($interpolate/$compile): port optimization from dart #6598
Changes from all commits
a3143f3
ef144e0
cd2ab14
688b494
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,32 +125,33 @@ function $InterpolateProvider() { | |
var startIndex, | ||
endIndex, | ||
index = 0, | ||
parts = [], | ||
length = text.length, | ||
separators = [], | ||
expressions = [], | ||
hasInterpolation = false, | ||
hasText = false, | ||
fn, | ||
exp, | ||
concat = []; | ||
|
||
while(index < length) { | ||
while(index < text.length) { | ||
if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) && | ||
((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) { | ||
(index != startIndex) && parts.push(text.substring(index, startIndex)); | ||
parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex))); | ||
if (index !== startIndex) hasText = true; | ||
separators.push(text.substring(index, startIndex)); | ||
expressions.push(fn = interpolateParse(exp = text.substring(startIndex + startSymbolLength, endIndex))); | ||
fn.exp = exp; | ||
index = endIndex + endSymbolLength; | ||
hasInterpolation = true; | ||
} else { | ||
// we did not find anything, so we have to add the remainder to the parts array | ||
(index != length) && parts.push(text.substring(index)); | ||
index = length; | ||
// we did not find an interpolation, so we have to add the remainder to the separators array | ||
if (index !== text.length) hasText = true; | ||
separators.push(text.substring(index)); | ||
break; | ||
} | ||
} | ||
|
||
if (!(length = parts.length)) { | ||
// we added, nothing, must have been an empty string. | ||
parts.push(''); | ||
length = 1; | ||
if (separators.length === expressions.length) { | ||
separators.push(''); | ||
} | ||
|
||
// Concatenating expressions makes it hard to reason about whether some combination of | ||
|
@@ -159,44 +160,62 @@ function $InterpolateProvider() { | |
// 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 && parts.length > 1) { | ||
if (trustedContext && hasInterpolation && (hasText || expressions.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 = length; | ||
concat.length = separators.length + expressions.length; | ||
var computeFn = function (values, context) { | ||
for(var i = 0, ii = expressions.length; i<ii; i++) { | ||
concat[2*i] = separators[i]; | ||
concat[(2*i)+1] = values ? values[i] : expressions[i](context); | ||
} | ||
concat[2*ii] = separators[ii]; | ||
return concat.join(''); | ||
}; | ||
|
||
fn = function(context) { | ||
return computeFn(null, context); | ||
}; | ||
fn.exp = text; | ||
fn.$$invoke = function (listener) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return function (values, oldValues, scope) { | ||
var current = computeFn(values, scope); | ||
listener(current, this.$$lastInter == null ? current : this.$$lastInter, scope); | ||
this.$$lastInter = current; | ||
}; | ||
}; | ||
fn.separators = separators; | ||
fn.expressions = expressions; | ||
return fn; | ||
} | ||
|
||
function interpolateParse(expression) { | ||
var exp = $parse(expression); | ||
return function (scope) { | ||
try { | ||
for(var i = 0, ii = length, part; i<ii; i++) { | ||
if (typeof (part = parts[i]) == 'function') { | ||
part = part(context); | ||
if (trustedContext) { | ||
part = $sce.getTrusted(trustedContext, part); | ||
} else { | ||
part = $sce.valueOf(part); | ||
} | ||
if (part === null || isUndefined(part)) { | ||
part = ''; | ||
} else if (typeof part != 'string') { | ||
part = toJson(part); | ||
} | ||
} | ||
concat[i] = part; | ||
var value = exp(scope); | ||
if (trustedContext) { | ||
value = $sce.getTrusted(trustedContext, value); | ||
} else { | ||
value = $sce.valueOf(value); | ||
} | ||
return concat.join(''); | ||
} | ||
catch(err) { | ||
if (value === null || isUndefined(value)) { | ||
value = ''; | ||
} else if (typeof value != 'string') { | ||
value = toJson(value); | ||
} | ||
return value; | ||
} catch(err) { | ||
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, | ||
err.toString()); | ||
err.toString()); | ||
$exceptionHandler(newErr); | ||
} | ||
}; | ||
fn.exp = text; | ||
fn.parts = parts; | ||
return fn; | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -314,8 +314,8 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) { | |
} | ||
for(var fns, j=0, jj=binding.length; j<jj; j++) { | ||
fns = binding[j]; | ||
if (fns.parts) { | ||
fns = fns.parts; | ||
if (fns.expressions) { | ||
fns = fns.expressions; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @juliemr would this change also affect protractor? how do you introspect interpolations in protractor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not require a change in Protractor. Protractor currently uses the element's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks! |
||
} else { | ||
fns = [fns]; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for clarifications:
We use
interpolateFn.$$invoke(listener)
so we just interpolate once and reuse the same instance for multiple invocations oflink
. This couldn't be done if we were to use dart's.setter
property