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

throttle() function causes Angular to not get stable #983

Open
pappkamerad opened this issue Mar 12, 2021 · 2 comments · May be fixed by #1344
Open

throttle() function causes Angular to not get stable #983

pappkamerad opened this issue Mar 12, 2021 · 2 comments · May be fixed by #1344
Labels

Comments

@pappkamerad
Copy link

When using your library with Angular, I noticed that the setTimeout() in your throttle() function is causing Angular to not get 'stable' for the given interval (default is 60s).

Angular considers itself 'unstable' when ZoneJS is seeing pending micro or macro tasks in the Angular zone. ('isStable' doc: https://angular.io/api/core/ApplicationRef#is-stable-examples)

The problem, as i understand it, here is that the throttle() gets executed within the Angular zone if Angular is present.

We use this 'isStable' flag for certain features that need to know if the given route has finished loading and the page rendering/processing is done.

So, as the general solution to this is, that you run your long running tasks outside of the Angular zone, my idea was to also run your throttle setTimeout function in a separate, new zone if there is window.Zone available.

Something like:

export default function throttle(fn, onThrottle, opts) {
  var context = this;
  var limit = opts.limit;
  var interval = opts.interval;
  var counter = 0;
  var timeoutId;
  var throttleZone = typeof Zone !== 'undefined' && Zone.root.fork({name: 'apm-throttle-zone'});

  return function () {
    counter++;

    if (typeof timeoutId === 'undefined') {
        var timeoutFn = function () {
          timeoutId = setTimeout(function () {
            counter = 0;
            timeoutId = undefined;
          }, interval);
        };

        if (throttleZone) {
          throttleZone.run(timeoutFn)
        } else {
          timeoutFn();
        }
    }

    if (counter > limit && typeof onThrottle === 'function') {
      return onThrottle.apply(context, arguments);
    } else {
      return fn.apply(context, arguments);
    }
  };
}

What do you guys think?

@vigneshshanmugam
Copy link
Member

Hmmm, Interesting and thanks for the detailed writeup.

We are working on updating our Angular integration and add support for the new versions >=9. We have moved the initialization logic of our code in to a separate zone

const apmInstance = this.ngZone.runOutsideAngular(() =>
this.apm.init(config)
)

Would this fix the problem that you are describing here?

@pappkamerad
Copy link
Author

I tried to do that first, but unfortunately it did not work for me, no.

I think the issue is, that this throttle is called from within the patched XHR and therefore always runs in the Angular zone.

pappkamerad pushed a commit to pappkamerad/apm-agent-rum-js that referenced this issue Feb 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants