-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Description
I'm submitting a...
[x] Performance issue
Current behavior
We (Akamai) develop a Real User Monitoring (RUM) JS library that monitors performance of web apps called Boomerang. Boomerang uses MutationObservers in order to capture data about the user experience in a framework agnostic way. In most cases Boomerang will be loaded asynchronously and will be run after site and Angular Javascript runs. At that point, NgZone has replaced MO with a zone aware version.
Depending on timings in the page, the MutationObserver object can be instantiated in the angular zone. When this occurs and our MO callback runs, Angular/NgZone marks the zone as unstable. Zone stability checks can cause DOM element updates/deletes/additions which then re-fires our MO causing an infinite cycle. This hangs the browser.
In the cases where we have see this occur so far have been when Angular calls into our code through our wrapped history.replaceState or history.pushState while in the angular zone. Our wrapped history functions can start a MutationObserver. Could Angular gate calls to browser APIs with runOutsideAngular?
In order to work around this, we will try to detect that NgZone/Zone.js is on the page and get the native MutationObserver object with window[window.Zone.__symbol__("MutationObserver")]. Tested in Angular 2, 4, & 6. Is this method of saving the native object and finding its new name expected to be available in future versions?
One of Boomerang's goals is to minimize the observer effect. We are also wary of using zone aware addEventListener, setTimeout, etc. which can trigger unneeded work in the base page. Our listeners/callbacks will never do work, modify DOM elements or trigger exceptions that need to be reacted to by first party code. Depending on the browser, we can run some code in requestIdleCallback which is not (yet?) instrumented by Zone.
Expected behavior
Use of MO will not cause an infinite loop
Environment
Observed in Angular 2, 4 and 6.