简体   繁体   中英

Really slow change detection in hybrid Angular app

We have a hybrid AngularJS / Angular 8 app, and we keep constantly running into issues with really slow change detection between components from different versions of the framework. Until now we've only had this problem when using AngularJS components inside Angular components. The common case is having a new Angular 8 form that has some old AngularJS components in it, and with some specific AngularJS components it can take anywhere between ~2 to ~10 seconds for the changes made in the component to propagate to the Angular form and for form validations to run. The UI doesn't hang or anything, it stays responsive, but there just seems to be a varying delay in communications between the different versions of the framework. Other AngularJS components in the same form might work seamlessly. We haven't found out the root cause for it yet, but we have found one reliable workaround; use $timeout(() => $scope.apply()); in the AngularJS component, usually in the $onChanges -listener. This triggers change detection in Angular and removes the delay.

Now we're facing it with an Angular component that is used inside an AngularJS component. We have a new Angular component that essentially wraps anNG Bootstrap datepicker , and after selecting a date in the datepicker, there is a varying delay of several seconds (up to around 10 seconds) before the parent AngularJS form realizes that any changes were made. Angular's upgrade guide mentions that you can use NgZone.run() to manually trigger change detection when using downgradeModule() (which we are), but we haven't found a way to get it working. The documentation doesn't really go into detail how run() should be used, either. We also tried ChangeDetectorRef.detectChanges() , to no avail.

I tried passing the AngularJS parent component's $scope down to the Angular component and using setTimeout(() => $scope.$apply()); in the Angular component after emitting a change event with an EventEmitter , and that did work; the delay was gone. But obviously this is not something we want to use for real.

Any suggestions on how to eliminate the change detection delay between AngularJS / Angular 8 components, either by manually triggering change detection from an Angular component or some other way?

In the end we didn't find any other solution than the one described in the question: passing the AngularJS $scope as an input parameter to the Angular component and wrapping the event emissions in $scope.$apply() , ie

$scope.$apply(() => valueChange.emit(value));

Based on the Angular upgrade guide , this seems to be the only way to get it working when using downgradeModule() .

Problems occur in AngularJS as it runs in cycles ($digset) . That way, AngularJS can evaluate the changes between the model and the view.

In every $digest cycle, the watchers are executed. This is the phase where Angular evaluates the expressions that are attached to the view and re-renders them back to the user.

There are a lot of times when operations in the client should and need to be done outside of the “Angular world”, which means Angular is not aware of these changes and does not reflect the changes to the user. There are several methods to resolve this issue, one as you mentioned using $timeout, methods are:

  1. $apply()
  2. $timeout()
  3. $digest()
  4. $evalAsync()

$evalAsync() was first introduced in AngularJS 1.2.X, and for me, it's the best method to use.

Before $evalAsync() was introduced, Officially answered by the Angular team, when you have issues with cycles and want to reflect changes from outside the “Angular world”, use $timeout().

After Angular has evolved and more users have experienced this known issue, the Angular team has created the $evalAsync(). This function will evaluate the expression during the current cycle or the next.

For more details: source

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM