diff --git a/benchmarks/largetable-bp/main.html b/benchmarks/largetable-bp/main.html
index f40353cb61e2..7fd8bdeec468 100644
--- a/benchmarks/largetable-bp/main.html
+++ b/benchmarks/largetable-bp/main.html
@@ -19,6 +19,7 @@
interpolation + fnInvocation:
ngBind + filter:
interpolation + filter:
+ ngModel:
@@ -77,6 +78,13 @@ interpolation with filter
{{column.i | noop}}:{{column.j | noop}}|
+
diff --git a/src/ng/interpolate.js b/src/ng/interpolate.js
index 5a0687cbcbcb..3b2461934643 100644
--- a/src/ng/interpolate.js
+++ b/src/ng/interpolate.js
@@ -88,6 +88,19 @@ function $InterpolateProvider() {
return '\\\\\\' + ch;
}
+ //TODO: this is the same as the constantWatchDelegate in parse.js
+ function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
+ var unwatch;
+ return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
+ return constantInterp(scope);
+ }, function constantInterpolateListener(value, old, scope) {
+ if (isFunction(listener)) {
+ listener.apply(this, arguments);
+ }
+ unwatch();
+ }, objectEquality);
+ }
+
/**
* @ngdoc service
* @name $interpolate
@@ -183,6 +196,19 @@ function $InterpolateProvider() {
* - `context`: evaluation context for all expressions embedded in the interpolated text
*/
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
+ // Provide a quick exit and simplified result function for text with no interpolation
+ if (!text.length || text.indexOf(startSymbol) === -1) {
+ var constantInterp;
+ if (!mustHaveExpression) {
+ var unescapedText = unescapeText(text);
+ constantInterp = function constantInterpolationFn() { return unescapedText; };
+ constantInterp.exp = text;
+ constantInterp.expressions = [];
+ constantInterp.$$watchDelegate = constantWatchDelegate;
+ }
+ return constantInterp;
+ }
+
allOrNothing = !!allOrNothing;
var startIndex,
endIndex,
diff --git a/test/ng/interpolateSpec.js b/test/ng/interpolateSpec.js
index 232244ede492..8124dc6f5695 100644
--- a/test/ng/interpolateSpec.js
+++ b/test/ng/interpolateSpec.js
@@ -125,6 +125,28 @@ describe('$interpolate', function() {
expect($rootScope.$countWatchers()).toBe(0);
}));
+
+ it('should stop watching strings with no expressions after first execution',
+ inject(function($interpolate, $rootScope) {
+ var spy = jasmine.createSpy();
+ $rootScope.$watch($interpolate('foo'), spy);
+ $rootScope.$digest();
+ expect(($rootScope.$$watchers || []).length).toBe(0);
+ expect(spy).toHaveBeenCalledWith('foo', 'foo', $rootScope);
+ expect(spy.calls.length).toBe(1);
+ })
+ );
+
+ it('should stop watching strings with only constant expressions after first execution',
+ inject(function($interpolate, $rootScope) {
+ var spy = jasmine.createSpy();
+ $rootScope.$watch($interpolate('foo {{42}}'), spy);
+ $rootScope.$digest();
+ expect(($rootScope.$$watchers || []).length).toBe(0);
+ expect(spy).toHaveBeenCalledWith('foo 42', 'foo 42', $rootScope);
+ expect(spy.calls.length).toBe(1);
+ })
+ );
});
describe('interpolation escaping', function() {
@@ -135,6 +157,7 @@ describe('$interpolate', function() {
it('should support escaping interpolation signs', inject(function($interpolate) {
+ expect($interpolate('\\{\\{')(obj)).toBe('{{');
expect($interpolate('{{foo}} \\{\\{bar\\}\\}')(obj)).toBe('Hello {{bar}}');
expect($interpolate('\\{\\{foo\\}\\} {{bar}}')(obj)).toBe('{{foo}} World');
}));