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

Infinite loop with MutationObserver + browser zoom #31712

Closed
eric-simonton-sama opened this issue Nov 22, 2017 · 9 comments
Closed

Infinite loop with MutationObserver + browser zoom #31712

eric-simonton-sama opened this issue Nov 22, 2017 · 9 comments
Assignees
Labels
area: zones Issues related to zone.js
Milestone

Comments

@eric-simonton-sama
Copy link

Using a combination of ngx-bootstrap tooltips, MutationObserver, and browser zooming it is possible to trigger an infinite loop that locks up the browser tab. Here is a plunker demonstrating the issue. Try different browser zoom levels, then mousing over the tooltips. For me it will lock the browser at 90% and 125% zoom, but not at 100% or 110%.

I filed this issue with a couple other libraries while trying to nail down the culprit:

@que-etc mentioned zone.js as his prime suspect in that second link, thus I am filing this issue.

Thanks for making Angular easier to use with this library!

@JiaLiPassion
Copy link
Contributor

JiaLiPassion commented Nov 23, 2017

@eric-simonton-sama , there is a walk around about this one.

import { Component, OnInit, NgZone } from '@angular/core';
import ResizeObserver from 'resize-observer-polyfill';

@Component({
  selector: 'ngx-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  array = new Array(20);

  constructor(private ngZone: NgZone) {
    this.ngZone.runOutsideAngular(() => {
          new ResizeObserver(() => {}).observe(document.body);
    });
  }
}

The reason is ,
zone.js patch MutationObserver to make sure the callback in zone.

So the infinite loop is,

resize ->document change(style) -> MutationObserver callback -> ngZone.checkStable -> ngbootstrap.positionService.positionElements -> document change(style) -> 'MutationObserver callback` ->....

so the walkaround is to make the MutationObserver callback outside of ngZone.
one side impact is the code in your ResizeObserver callback, it will not auto update the UI.

@eric-simonton-sama
Copy link
Author

Thank you for the workaround. To fix this in our real application it sounds like we would do as you suggest here, then manually trigger change detection from our resize handler when needed. That's better than having the browser crash!

@cary-smith
Copy link

So we have recently run into this too (using 0.8.26). Weird part is, the components using the ResizeObserver and MutationObservers are built using StencilJS so they are not part of the Angular ecosystem. Are there workarounds for 3rd party libraries?

@notbear
Copy link

notbear commented Jul 18, 2019

Trying to integrate a custom component (WebComponent v1) with Angular app. The component uses MutationObserver for observing changes in native control, but falls into infinite loop while placed into Angular app.

Template in the application:

<my-custom-select>
  <select formControlName="myOption">
    <option *ngFor="let option of options$ | async" [value]="option">{{ option }}</option>
 </select>
</my-custom-select>

In my component class:

this._optionsObserver = new MutationObserver(()=>{ /* the callback */})
this._optionsObserver.observe(this.select, {childList: true, subtree: true})

Tried a proposed workaround with instantiating window[window.Zone.__symbol__("MutationObserver")] but falling into loop again.

I'd appreciate any suggestion.

@JiaLiPassion
Copy link
Contributor

@notbear, could you create a reproduce repo?

@JiaLiPassion JiaLiPassion transferred this issue from angular/zone.js Jul 21, 2019
@JiaLiPassion JiaLiPassion self-assigned this Jul 21, 2019
@JiaLiPassion JiaLiPassion added the area: zones Issues related to zone.js label Jul 21, 2019
@ngbot ngbot bot added this to the needsTriage milestone Jul 21, 2019
@notbear
Copy link

notbear commented Jul 25, 2019

@JiaLiPassion , sure. I borrowed the example from #31483 which seems to be very similar issue. During investigation, I noticed that webcomponents are not necessary to reproduce this bug. See examples:

The getName method returns a new object instance. Luckily, unwrapping the MutationObserver fixes the issue:
https://stackblitz.com/edit/angular-mutationobserver-object?file=src/app/app.component.ts

But if you work with collection which reinstatiates object items like in the method getOptions, nothing helps.
https://stackblitz.com/edit/angular-mutationobserver-collection?file=src/app/app.component.ts

@notbear
Copy link

notbear commented Sep 24, 2019

Hi @JiaLiPassion

Related tickets #26948 and #31483 were recently closed because of inactivity.

I've just checked the example provided last time using latest versions of Angular and Zone (see versions below) and the issue still exists.

But luckily... the known workaround with unwrapping Zone previously worked only for plain objects. Now it seems to help also for collections. Could you comment or confirm that it's been fixed somehow?

    "@angular/animations": "~8.2.7",
    "@angular/common": "~8.2.7",
    "@angular/compiler": "~8.2.7",
    "@angular/core": "~8.2.7",
    "@angular/forms": "~8.2.7",
    "@angular/platform-browser": "~8.2.7",
    "@angular/platform-browser-dynamic": "~8.2.7",
    "@angular/router": "~8.2.7",
    "rxjs": "~6.4.0",
    "tslib": "^1.10.0",
    "zone.js": "~0.9.1"

@jelbourn
Copy link
Member

jelbourn commented Nov 2, 2020

@IgorMinar and I looked at this and we think this is at least working as expected. Angular uses zones to drive change detection, so using APIs like MutationObserver and ResizeObserver to then trigger further change detections is inherently prone to infinite loops. The advice here would be to generally listen to these outside of the zone and exercise more specific control over calling into change detection.

@jelbourn jelbourn closed this as completed Nov 2, 2020
@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 Dec 3, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: zones Issues related to zone.js
Projects
None yet
Development

No branches or pull requests

5 participants