Thanks to visit codestin.com
Credit goes to github.com

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

fix($rootScope): when adding/removing watchers during $digest #15424

Conversation

gkalpak
Copy link
Member

@gkalpak gkalpak commented Nov 23, 2016

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Bug fix.

What is the current behavior? (You can also link to an open issue here)
Adding a watcher during a $digest (i.e. from within a watcher), results in the next watcher getting skipped. Similarly, removing a watcher during a $digest could result in the current watcher being run twice (if the removed watcher had not run yet in the current $digest).

What is the new behavior (if this is a feature change)?
Adding/Removing watchers during a $digest works as expected.

Does this PR introduce a breaking change?
No.

Please check if the PR fulfills these requirements

Other information:
This commit fixes both cases by keeping track of the current watcher index during a digest and properly updating it when adding/removing watchers.

There might be a tiny extra overhead due to looking up $$digestWatchIndex on scope.$$watchers during the $digest.

Fixes #15422

Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

This commit fixes both cases by keeping track of the current watcher index
during a digest and properly updating it when adding/removing watchers.

Fixes angular#15422
@jcompagner
Copy link

looks good to me, i will test (patch my 158 install) with that code tomorrow to see how it works but at first sight that should fix it

one thing: "should not skip watchers when removing a watcher during digest'"

thats not really the case, for removing its not really skipping right? its more about not executing the same watch again? i think this check:

expect(log).toEqual([1, 2, 1, 2]);

would be without your fix:

expect(log).toEqual([1, 1, 2, 1, 2]);

right?

@jcompagner
Copy link

i patched my 158 install and i don't need the evalAsync patch that i now had in my code
it seems to work fine (also going through the application i don't notice anything weird)

@Narretz
Copy link
Contributor

Narretz commented Nov 24, 2016

We should definitely test this for performance.

@jcompagner
Copy link

the only thing that is really changed for digest() is that instead of a local variable we now have a scoped variable on a object. Anybody know what that lookup/assignment cost? Is that really measurable ?

i think the code in add/remove watch shouldn't be to much to worry about because that shouldn't really be called in high volume (like the digest cycle)

@gkalpak
Copy link
Member Author

gkalpak commented Nov 24, 2016

Yeah, the only change that matters (performance-wise) is the switch from a local variable to a property lookup. I doubt it will have any noticeable impact (compared to all other operations typically run alongside).

I meassured the duration of the digest (without any changes) in a finished instance of the largetable/ngBind benchmark (>40.000 watchers) and I didn't see any difference. In both cases (before and after this change) the duration was ~13-14ms.

@petebacondarwin
Copy link
Contributor

LGTM

@gkalpak gkalpak closed this in 1c0c260 Dec 9, 2016
gkalpak added a commit that referenced this pull request Dec 9, 2016
Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

This commit fixes both cases by keeping track of the current watcher index
during a digest and properly updating it when adding/removing watchers.

Fixes #15422

Closes #15424
@gkalpak gkalpak deleted the fix-rootScope-add-remove-watchers-during-digest branch December 9, 2016 08:45
gkalpak added a commit that referenced this pull request Dec 9, 2016
Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

This commit fixes both cases by keeping track of the current watcher index
during a digest and properly updating it when adding/removing watchers.

Fixes #15422

Closes #15424
ellimist pushed a commit to ellimist/angular.js that referenced this pull request Mar 15, 2017
Previously, adding a watcher during a `$digest` (i.e. from within a watcher),
would result in the next watcher getting skipped. Similarly, removing a watcher
during a `$digest` could result in the current watcher being run twice (if the
removed watcher had not run yet in the current `$digest`).

This commit fixes both cases by keeping track of the current watcher index
during a digest and properly updating it when adding/removing watchers.

Fixes angular#15422

Closes angular#15424
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

digest is skipping watches when a watch addes watches in its watch function.
5 participants