Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

$watch override makes one-time bindings in expressions to never clear the associated watch #109

Closed
raulmt opened this issue Sep 9, 2015 · 2 comments

Comments

@raulmt
Copy link

raulmt commented Sep 9, 2015

This function wrapping done to measure the watchExpression call's performance (https://github.com/angular/angular-hint/blob/master/src/modules/scopes.js#L110-L120) makes one-time binding expressions and also literal string expressions to keep the watcher on scope and executing it forever.

I think the problem is the wrapping function doesn't inherit properties of the original function. One of the missing properties I think causes this wrong behaviour is $$watchDelegate which, in case of one-time bindings and literal string bindings functions has the logic to remove the watch after the first stable call.

The original $watch function checks wether watchExpression function has a $$watchDelegate and calls it if it does. And after adding this file (angular-hint), those wrapped watchExpression functions will never have a $$watchDelegate so the watch will not be removed.

I had this issue while using angular Batarang (Angular's Chrome extension). I noticed that while having Batarang active, adding :: to bracket expressions didn't make me lower the watchers count.

I'm using latest Batarang version (0.8.6) which includes angular-hint 0.3.4.

@erwinmombay
Copy link
Contributor

thats true, that definitely is a problem. i'll take a look if theres anything we can do, feel free to add more comments/suggestions or send a PR if you think up of anything as well. appreciate you reporting this!

@OACDesigns
Copy link

OACDesigns commented Dec 27, 2016

just a bump on this, there's a small but important part missing in the isOneTimeBindExp that means {{ ::value }} doesn't get counted as a one-time binding, while {{::value}} does.
I've submitted a PR to fix this: #122

gkalpak added a commit to gkalpak/angular-hint that referenced this issue Mar 30, 2017
Previously, one-time expressions were supposed to not trigger perf timers. There
were a couple of issues with the implementation:

1. One-time expressions were not detected as such if there was whitespace before
   the `::`.
2. It depended on internal AngularJS implementation details in a way that would
   fail to identify certain usecases (e.g. multiple interpolations in a single
   attribute value or node text).
3. Time spent on the initial evaluation of the one-time expressions would not be
   accounted for, but could still impact the duration of the first `$digest`.
4. While it is not common, there are cases were one-time expressions don't
   settle immediately. In such cases, their impact on the `$digest` should not
   be ignored.

This commit fixes the above issues by ensuring that only the "final" call to
`$watch` is intercepted (in contrast to intermediate calls that might call a
`$$watchDelegate`, which will then create the actual `$watch`er). One-time
expressions are intercepted normally and stop triggering perf times as soon as
their `unwatch` function is called.

Although the dependency on internal AngularJS implementation details could not
be avoided, the new implementation is a little more robust, as it relies on
fewer and less brittle details :D

Fixes angular#109
Closes angular#122
gkalpak added a commit that referenced this issue Mar 30, 2017
Previously, one-time expressions were supposed to not trigger perf timers. There
were a couple of issues with the implementation:

1. One-time expressions were not detected as such if there was whitespace before
   the `::`.
2. It depended on internal AngularJS implementation details in a way that would
   fail to identify certain usecases (e.g. multiple interpolations in a single
   attribute value or node text).
3. Time spent on the initial evaluation of the one-time expressions would not be
   accounted for, but could still impact the duration of the first `$digest`.
4. While it is not common, there are cases were one-time expressions don't
   settle immediately. In such cases, their impact on the `$digest` should not
   be ignored.

This commit fixes the above issues by ensuring that only the "final" call to
`$watch` is intercepted (in contrast to intermediate calls that might call a
`$$watchDelegate`, which will then create the actual `$watch`er). One-time
expressions are intercepted normally and stop triggering perf times as soon as
their `unwatch` function is called.

Although the dependency on internal AngularJS implementation details could not
be avoided, the new implementation is a little more robust, as it relies on
fewer and less brittle details :D

Fixes #109
Closes #122

Closes #124
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants