angular: UpgradeModule $rootScope.$digest error even though we are not triggering a digest manually.
I’m submitting a…
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
This issue relates to this stackOverflow issue and this conversation and this conversation in gitter
We authorize a user with Google SignIn, and then use ui-router to send them to the landing page, doing this causes a $rootScope digest already in process error.
We do not trigger a $digest / $apply explicitly. We don’t route a user with $location, location, or anything. We use ui-router, but it’s not ui-router that triggers the $digest within the $digest. As far as I can tell, it appears to be this line in NgUpgrade.
Expected behavior
No $rootScope.$digest error
Minimal reproduction of the problem with instructions
- Go here: https://portal.telnyx.com/index-nomin.html#/
- Create an account.
- Log out.
- Open dev tools (so you can “clear cache and hard reload”)
- “clear cache and hard reload”
- Sign in with Google Sign In.
If you do not see a digest error in console, repeat the above process up to 5 times and you will eventually see the error. Here is a short snippet of the code:
What is the motivation / use case for changing the behavior?
If it’s a bug it’s a bug.
Environment
Angular version: X.Y.Z
4.2.4
Browser:
- [x] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: XX
- Platform:
Others:
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 20 (11 by maintainers)
@andrewl-telnyx: BTW, something I noticed while looking at the code is that the
DSCache#setRecycleFreq()
is usingsetInterval()
to schedule an operation once per second for each cache (I saw 3 of them iirc). SincesetInterval
is called from inside AngularJS, which is bootstraped inside the Angular zone, it means that 3 times per second you get a newonMicrotaskEmpty
emission, i.e. 3x Angular change detection and 3x$digest
per second (for no change). I took a quick look, so take it with a grain of salt. But worth looking into.(This is probably not related to this issue - just mentioning it as a heads-up.)
You might also be interested in a new API that will be introduced in 5.x, which will allow you to bootstrap AngularJS outside the Angular zone and avoid the
$digest
on eachonMicrotaskEmpty
emission. The docs are still in progress, but you can get a preview here.It is more suited for architectures that try to keep the two parts decoupled, so not sure if it works for you. Not that interleaving Angular/AngularJS components won’t work, but you might have to manually trigger change detections too often (e.g. if you rely on “global” app state through services, instead of propagating it via component inputs).
@andrewl-telnyx , @petebacondarwin, I would like to help to debug about the
Zone
issue, I will try to debug whyzone
not triggeronMicroTaskEmpty
Glad you have a workaround. If you find that you start missing change detections then you’ll know where to look.
The reason your solution works is that you are no longer running the
handleAuth2Result
function inside the “Angular” zone, which means that when the popstate event is triggered our ngUpgradeonMicroTaskEmpty
handler is not called, which in turn does not trigger the digest.Normally this is a dangerous thing to do, because anything that follows in that zone (all async tasks that are triggered via that original call to
handleAuth2Result
) will not trigger change detection between the AngularJS and Angular parts of the app.But in this case I imagine that it is not going to impact your app too much. I guess it depends on what is in that handler.
So… the underlying process looks like this:
$location
(maybe the Google Auth library or maybe ui-router - the latter I think)$location
’s watcher, which tries to resynchronise itself with the browser URLwindow.location.hash
PopState
eventPlatformLocation
is being used, which sets up a handler forPopState
events.ZoneAwareCallback
MicroTaskEmpty
hookThe question I am having trouble answering is what is it about this first login that causes the Zone library to trigger the hook.
I think we might need to pull in the big guns (@mhevery perhaps) to help dig through what is happening in Zones.
@petebacondarwin we turned off bugsnag and commented it out in code, and the problem still occurs. we’re going to get you a non minified version here in a bit.