Skip to content

Third party use of MutationObserver can cause the browser to hang #26948

@querymetrics

Description

@querymetrics

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtime

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions