I'm submitting a...
[X] Regression (a behavior that used to work and stopped working in a new release)
[ ] 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
In #18107 the DomEventsPlugin was changed to bypass Zone.js when adding event listeners. This improves performance when scheduling these events, but it forces their handler to run in the Angular Zone, regardless of which Zone the addEventListener call originated from.
Expected behavior
In ngUpgrade, a $rootScope.$digest is called every time the NgZone is invoked. For certain events that fire frequently (scroll, mouseover, mouseout, etc), these handlers would trigger potentially expensive $digest calls frequently.
We worked around this by running Angular in a custom zone. Our custom zone would intercept when these event handlers were scheduled and instead schedule them in the root zone, thus running their handler outside of NgZone and avoiding the expensive $digest call.
This workaround is no longer an option. By default, the EventManagerPlugin will schedule events without Zone.js and we have no way to alter this behavior. This isn't an issue for us as ngUpgradeLite has solved our performance problems, but other teams using ngUpgrade might have had a similar solution.
Example of old workaround
const customZone = Zone.current.fork({
name: 'event blacklist',
onScheduleTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task):
Task => {
// Blacklist scroll, mouse, and request animation frame events.
if ((task.type === 'eventTask' || task.type === 'macroTask') &&
isBlacklistedEvent(task.source)) {
task.cancelScheduleRequest();
// Schedule task in root zone.
return Zone.root.scheduleTask(task);
} else {
return delegate.scheduleTask(target, task);
}
}
});
then, during bootstrap...
customZone.run(() => {
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then((ref) => {
const adapter = ref.injector.get(UpgradeModule) as UpgradeModule;
const zone = ref.injector.get(NgZone);
zone.run(() => {
adapter.bootstrap(el, modules);
});
});
});
New workaround
We still want to control how handlers for these events are run. However, it seems that since EventManagerPlugin is not intended to be a public API, our only option is to make a custom RendererFactory.
I don't know if this is a change in behavior that needs to be fixed, or just something that needs to be documented.
I'm submitting a...
Current behavior
In #18107 the DomEventsPlugin was changed to bypass Zone.js when adding event listeners. This improves performance when scheduling these events, but it forces their handler to run in the Angular Zone, regardless of which Zone the addEventListener call originated from.
Expected behavior
In ngUpgrade, a
$rootScope.$digestis called every time the NgZone is invoked. For certain events that fire frequently (scroll, mouseover, mouseout, etc), these handlers would trigger potentially expensive $digest calls frequently.We worked around this by running Angular in a custom zone. Our custom zone would intercept when these event handlers were scheduled and instead schedule them in the root zone, thus running their handler outside of NgZone and avoiding the expensive $digest call.
This workaround is no longer an option. By default, the EventManagerPlugin will schedule events without Zone.js and we have no way to alter this behavior. This isn't an issue for us as ngUpgradeLite has solved our performance problems, but other teams using ngUpgrade might have had a similar solution.
Example of old workaround
then, during bootstrap...
New workaround
We still want to control how handlers for these events are run. However, it seems that since EventManagerPlugin is not intended to be a public API, our only option is to make a custom RendererFactory.
I don't know if this is a change in behavior that needs to be fixed, or just something that needs to be documented.