Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(upgrade): infinite digests with setTimeout (repro inside) #6385

Closed
andreialecu opened this issue Jan 10, 2016 · 15 comments
Closed

bug(upgrade): infinite digests with setTimeout (repro inside) #6385

andreialecu opened this issue Jan 10, 2016 · 15 comments

Comments

@andreialecu
Copy link
Contributor

angular2/upgrade has a bug that occurs when an angular1 watcher calls setTimeout, as is the case with many angular1 components.

Repro: http://plnkr.co/edit/5iCEQOSOer5c630FStXv?p=preview

This results in infinite angular1 digests because of this line:

https://github.com/angular/angular/blob/master/modules/angular2/src/upgrade/upgrade_adapter.ts#L341

Changing ngZone.run to ngZone.runOutsideAngular there seems to fix it or make it more manageable.

andreialecu added a commit to andreialecu/angular that referenced this issue Jan 10, 2016
andreialecu added a commit to andreialecu/angular that referenced this issue Jan 10, 2016
@andreialecu andreialecu changed the title bug: infinite digests with angular2/upgrade and setTimeout (repro inside) bug(upgrade): infinite digests with setTimeout (repro inside) Jan 11, 2016
andreialecu added a commit to andreialecu/angular that referenced this issue Jan 13, 2016
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Dec 16, 2016
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Dec 17, 2016
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Dec 17, 2016
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Dec 18, 2016
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 6, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 6, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 8, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 11, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 13, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 13, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034
mhevery pushed a commit that referenced this issue Jan 17, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for #6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix #6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes #10660, #12318, #12034

PR Close #13812
mhevery pushed a commit that referenced this issue Jan 19, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for #6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix #6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes #10660, #12318, #12034

PR Close #13812
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 20, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See angular#13812
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 20, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See angular#13812
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 20, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See angular#13812
mhevery pushed a commit that referenced this issue Jan 27, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for #6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix #6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See #13812

PR Close #14039
mhevery pushed a commit that referenced this issue Jan 27, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for #6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix #6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See #13812

PR Close #14039
wKoza pushed a commit to wKoza/angular that referenced this issue Feb 12, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034

PR Close angular#13812
@dbpieter
Copy link

dbpieter commented Feb 16, 2017

@petebacondarwin Shouldn't this bug be reopened after #13812 ?

We are experiencing issues resulting in the infamous "$digest already in progress"

@louwie17
Copy link

louwie17 commented Mar 2, 2017

@petebacondarwin Did you have any updates on this problem, or a tentative idea on how to tackle/implement it?

heathkit added a commit to heathkit/angular that referenced this issue Mar 15, 2017
This fixes angular#6385 by running `$rootScope.$digest` in a child zone. This
prevents tasks started in the digest cycle from triggering the digest
again, thus preventing the infinite loop.
heathkit added a commit to heathkit/angular that referenced this issue Mar 15, 2017
This fixes angular#6385 by running `$rootScope.$digest` in a child zone. This
prevents tasks started in the digest cycle from triggering the digest
again, thus preventing the infinite loop.
heathkit added a commit to heathkit/angular that referenced this issue Mar 15, 2017
This fixes angular#6385 by running `$rootScope.$digest` in a child zone. This
prevents tasks started in the digest cycle from triggering the digest
again, thus preventing the infinite loop.
heathkit added a commit to heathkit/angular that referenced this issue Mar 16, 2017
This fixes angular#6385 by running `$rootScope.$digest` in a child zone. This
prevents tasks started in the digest cycle from triggering the digest
again, thus preventing the infinite loop.
heathkit added a commit to heathkit/angular that referenced this issue Apr 4, 2017
This fixes angular#6385 by running `$rootScope.$digest` in a child zone. This
prevents tasks started in the digest cycle from triggering the digest
again, thus preventing the infinite loop.
@kempcarlos
Copy link

@petebacondarwin any update? Will this be fixed in the near future?

@KirillMetrik
Copy link

+1 Any update on this please?

@dreef3
Copy link

dreef3 commented Aug 26, 2017

Hi,
This issue effectively prevents us from upgrading a hybrid ng1/ng2 app to Angular 2.4.6+. Do you have any thoughts on how this could be resolved? I'd submit a PR then.

What about the comment here that states that #13812 also reverted the line which replaced $digest with $evalAsync?

This was originally introduced in #9054.

@andreialecu
Copy link
Contributor Author

I'm also blocked by this. Haven't been able to upgrade to new versions since this was reverted.

I'm not sure the frequency of this issue is low either. It's hard to track because infinite digests still allow the app run properly but it's just that the performance is very bad. I was only able to realize what was happening via a chrome extension that was showing me angular 1 digest frequency.

@gkalpak
Copy link
Member

gkalpak commented Aug 26, 2017

We are generally not keen on changing $digest to $evalAsync for the digest that is run when the microtask queue is empty, because this tends to hide programming errors (which often have hard-to-track-down performance implications).

This unfortunately means that running setTimeout in a watcher will lead to infinite digest errors, unless you change it to run outside of the Angular zone.

To be clear, you can still use setTimeout in the watch listener function:

scope.$watch(
  () => {
    // Watch function.
    // Do NOT use `setTimeout()` here (unless you explicitly run it outside the Angular zone).
  },
  () => {
    // Watch listener function.
    // You can use `setTimeout()` here.
  }
)

The new downgradeModule(), which decouples the change detections of the two frameworks, could possibly help in such situations. (Docs will be added with #18487.)

juleskremer pushed a commit to juleskremer/angular that referenced this issue Aug 28, 2017
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034

PR Close angular#13812
juleskremer pushed a commit to juleskremer/angular that referenced this issue Aug 28, 2017
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See angular#13812

PR Close angular#14039
@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018
@KirillMetrik
Copy link

Have you please got any update on this? The bug really prevents us from upgrading to latest Angular and we're quite stuck with AngularJS 1.

@splincode
Copy link
Contributor

splincode commented Jul 30, 2018

@andreialecu @trotyl What do you think? Is the issue relevant?

It seems to me that the problem is connected with calling setTimeout
#24133

@mhevery
Copy link
Contributor

mhevery commented Aug 7, 2018

Will not fix: not feasible.

@mhevery mhevery closed this as completed Aug 7, 2018
@KirillMetrik
Copy link

How should we address upgrading our app from Angular 1 if this is not feasible? We're having a big enterprise project and have chosen AngularJS (1) because it was well supported and promoted by Google. One of the reasons was that we were hoping the project will stay maintanable in time. Instead, Angular 2-6 is a completely new framework, practically incompatible with AngularJS and there is no way to upgrade because of this issue.
@mhevery do you please have any idea what to do in our case? Or should we just throw away all our code and write everything from scratch?
If that's the only option it might make sense for us to switch to React.

@gkalpak
Copy link
Member

gkalpak commented Oct 5, 2018

@KirillMetrik, the thing that is not feasible is using setTimeout() in a watch function, unless you either explicitly run it outside the Angular zone or use downgradeModule() (see #6385 (comment)).

All this means is that (if you choose not to use downgradeModule()) you have to modify your code to either not use setTimeout() inside a watch function (which is weird anyway) or modify your code to run it outside the Angular zone. I don't see how this is preventing your from upgrading. You will have to change that code anyway sooner or later (i.e. you will have to get rid of scope.$watch() at some point).

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 14, 2019
idlechara pushed a commit to idlechara/angular that referenced this issue Apr 27, 2021
This commit effectively reverts 7e0f02f
as it was an invalid fix for angular#6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix angular#6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

Closes angular#10660, angular#12318, angular#12034

PR Close angular#13812
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.