-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix($parse): do not shallow-watch inputs when wrapped in an interceptor fn #16018
Changes from all commits
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 |
---|---|---|
|
@@ -622,6 +622,9 @@ function isStateless($filter, filterName) { | |
return !fn.$stateful; | ||
} | ||
|
||
var PURITY_ABSOLUTE = 1; | ||
var PURITY_RELATIVE = 2; | ||
|
||
// Detect nodes which could depend on non-shallow state of objects | ||
function isPure(node, parentIsPure) { | ||
switch (node.type) { | ||
|
@@ -634,18 +637,18 @@ function isPure(node, parentIsPure) { | |
|
||
// Unary always convert to primative | ||
case AST.UnaryExpression: | ||
return true; | ||
return PURITY_ABSOLUTE; | ||
|
||
// The binary + operator can invoke a stateful toString(). | ||
case AST.BinaryExpression: | ||
return node.operator !== '+'; | ||
return node.operator !== '+' ? PURITY_ABSOLUTE : false; | ||
|
||
// Functions / filters probably read state from within objects | ||
case AST.CallExpression: | ||
return false; | ||
} | ||
|
||
return (undefined === parentIsPure) || parentIsPure; | ||
return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure; | ||
} | ||
|
||
function findConstantAndWatchExpressions(ast, $filter, parentIsPure) { | ||
|
@@ -873,7 +876,7 @@ ASTCompiler.prototype = { | |
forEach(inputs, function(input) { | ||
result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's')); | ||
if (input.isPure) { | ||
result.push(input.name, '.isPure=true;'); | ||
result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';'); | ||
} | ||
}); | ||
if (inputs.length) { | ||
|
@@ -1960,10 +1963,16 @@ function $ParseProvider() { | |
fn.$$watchDelegate = watchDelegate; | ||
fn.inputs = parsedExpression.inputs; | ||
} else if (!interceptorFn.$stateful) { | ||
// If there is an interceptor, but no watchDelegate then treat the interceptor like | ||
// we treat filters - it is assumed to be a pure function unless flagged with $stateful | ||
// Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate | ||
fn.$$watchDelegate = inputsWatchDelegate; | ||
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]; | ||
fn.inputs = (parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]).map(function(e) { | ||
// Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a | ||
// potentially non-pure interceptor function. | ||
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. I do not understand this comment and how this matches with the previous comment. Here it is stated that the interceptor can be non-pure, but before it is assumed that the interceptor is pure. 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. I think the comment a few lines up is using the wrong terminology. I think it should just say "it is assumed to be non-$stateful". I'm not 100% sure if I'm using the "pure" terminology correct here, but I'll try to update the comments similar to #16015 which I think clears this up more. See: https://github.com/angular/angular.js/pull/16015/files#diff-780de070ede30180f6aedb6c5f7d57caR1964 To (try) summarizing:
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. I've updated the comment above this to remove the (incorrect) use of "pure function" terminology. |
||
if (e.isPure === PURITY_RELATIVE) { | ||
return function depurifier(s) { return e(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. Creating these extra closures and executing them per-digest when watching things is a bit of a concern. But any alternative I've thought of would involve modifying https://github.com/jbedard/angular.js/blob/5c3f3ffb7478eadc72c4f90b6a1964557e355538/src/ng/parse.js#L1856 which would effect everything, not only interceptor inputs. 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. where is 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. That's just the name of this wrapper function (which removes the |
||
} | ||
return e; | ||
}); | ||
} | ||
|
||
return fn; | ||
|
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.
Better terminology for these...?