Skip to content

Commit ec20908

Browse files
committed
Optimizing Interpolation Watches With A Watch Delegate
1 parent 555e7c4 commit ec20908

File tree

2 files changed

+58
-9
lines changed

2 files changed

+58
-9
lines changed

src/interpolate.js

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ function $InterpolateProvider() {
2424
var index = 0;
2525
var parts = [];
2626
var expressions = [];
27+
var expressionFns = [];
28+
var expressionPositions = [];
2729
var startIndex, endIndex, exp, expFn;
2830
while (index < text.length) {
2931
startIndex = text.indexOf('{{', index);
@@ -36,26 +38,45 @@ function $InterpolateProvider() {
3638
}
3739
exp = text.substring(startIndex + 2, endIndex);
3840
expFn = $parse(exp);
39-
parts.push(expFn);
4041
expressions.push(exp);
42+
expressionFns.push(expFn);
43+
expressionPositions.push(parts.length);
44+
parts.push(expFn);
4145
index = endIndex + 2;
4246
} else {
4347
parts.push(unescapeText(text.substring(index)));
4448
break;
4549
}
4650
}
4751

52+
function compute(values) {
53+
_.forEach(values, function(value, i) {
54+
parts[expressionPositions[i]] = stringify(value);
55+
});
56+
return parts.join('');
57+
}
58+
59+
4860
if (expressions.length || !mustHaveExpressions) {
4961
return _.extend(function interpolationFn(context) {
50-
return _.reduce(parts, function(result, part) {
51-
if (_.isFunction(part)) {
52-
return result + stringify(part(context));
53-
} else {
54-
return result + part;
55-
}
56-
}, '');
62+
var values = _.map(expressionFns, function(expressionFn) {
63+
return expressionFn(context);
64+
});
65+
return compute(values);
5766
}, {
58-
expressions: expressions
67+
expressions: expressions,
68+
$$watchDelegate: function(scope, listener) {
69+
var lastValue;
70+
return scope.$watchGroup(expressionFns, function(newValues, oldValues) {
71+
var newValue = compute(newValues);
72+
listener(
73+
newValue,
74+
(newValues === oldValues ? newValue : lastValue),
75+
scope
76+
);
77+
lastValue = newValue;
78+
});
79+
}
5980
});
6081
}
6182

test/interpolate_spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,32 @@ describe('$interpolate', function() {
115115
expect(interp).not.toBeFalsy();
116116
});
117117

118+
it('uses a watch delegate', function() {
119+
var injector = createInjector(['ng']);
120+
var $interpolate = injector.get('$interpolate');
121+
var interp = $interpolate('has an {{expr}}');
122+
expect(interp.$$watchDelegate).toBeDefined();
123+
});
124+
125+
it('correctly returns new and old value when watched', function() {
126+
var injector = createInjector(['ng']);
127+
var $interpolate = injector.get('$interpolate');
128+
var $rootScope = injector.get('$rootScope');
129+
130+
var interp = $interpolate('{{expr}}');
131+
var listenerSpy = jasmine.createSpy();
132+
133+
$rootScope.$watch(interp, listenerSpy);
134+
$rootScope.expr = 42;
135+
136+
$rootScope.$apply();
137+
expect(listenerSpy.calls.mostRecent().args[0]).toEqual('42');
138+
expect(listenerSpy.calls.mostRecent().args[1]).toEqual('42');
139+
140+
$rootScope.expr++;
141+
$rootScope.$apply();
142+
expect(listenerSpy.calls.mostRecent().args[0]).toEqual('43');
143+
expect(listenerSpy.calls.mostRecent().args[1]).toEqual('42');
144+
});
145+
118146
});

0 commit comments

Comments
 (0)